1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005-2009 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"
43 #include <libunwind/DwarfInstructions.hpp>
44 #include <libunwind/AddressSpace.hpp>
45 #include <libunwind/Registers.hpp>
49 // To implement architecture xxx, you must write template specializations for the following six methods:
50 // Reader<xxx>::validFile()
51 // Reader<xxx>::validSectionType()
52 // Reader<xxx>::addRelocReference()
53 // Reference<xxx>::getDescription()
59 extern __attribute__((noreturn
)) void throwf(const char* format
, ...);
60 extern void warning(const char* format
, ...);
63 namespace relocatable
{
70 bool operator()(const ObjectFile::Reference
* left
, const ObjectFile::Reference
* right
)
72 return ( left
->getFixUpOffset() < right
->getFixUpOffset() );
78 template <typename A
> class Reader
;
82 AtomAndOffset(ObjectFile::Atom
* a
=NULL
) : atom(a
), offset(0) {}
83 AtomAndOffset(ObjectFile::Atom
* a
, uint32_t off
) : atom(a
), offset(off
) {}
84 ObjectFile::Atom
* atom
;
90 class Reference
: public ObjectFile::Reference
93 typedef typename
A::P P
;
94 typedef typename
A::P::uint_t pint_t
;
95 typedef typename
A::ReferenceKinds Kinds
;
97 Reference(Kinds kind
, const AtomAndOffset
& at
, const AtomAndOffset
& toTarget
);
98 Reference(Kinds kind
, const AtomAndOffset
& at
, const AtomAndOffset
& fromTarget
, const AtomAndOffset
& toTarget
);
99 Reference(Kinds kind
, const AtomAndOffset
& at
, const char* toName
, uint32_t toOffset
);
101 virtual ~Reference() {}
104 virtual ObjectFile::Reference::TargetBinding
getTargetBinding() const;
105 virtual ObjectFile::Reference::TargetBinding
getFromTargetBinding() const;
106 virtual uint8_t getKind() const { return (uint8_t)fKind
; }
107 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc
; }
108 virtual const char* getTargetName() const { return (fToTarget
.atom
!= NULL
) ? fToTarget
.atom
->getName() : fToTargetName
; }
109 virtual ObjectFile::Atom
& getTarget() const { return *fToTarget
.atom
; }
110 virtual uint64_t getTargetOffset() const { return (int64_t)((int32_t)fToTarget
.offset
); }
111 virtual ObjectFile::Atom
& getFromTarget() const { return *fFromTarget
.atom
; }
112 virtual const char* getFromTargetName() const { return (fFromTarget
.atom
!= NULL
) ? fFromTarget
.atom
->getName() : fFromTargetName
; }
113 virtual void setTarget(ObjectFile::Atom
& target
, uint64_t offset
) { fToTarget
.atom
= &target
; fToTarget
.offset
= offset
; }
114 virtual void setToTargetOffset(uint64_t offset
) { fToTarget
.offset
= offset
; }
115 virtual void setFromTarget(ObjectFile::Atom
& target
) { fFromTarget
.atom
= &target
; }
116 virtual void setFromTargetName(const char* name
) { fFromTargetName
= name
; }
117 virtual void setFromTargetOffset(uint64_t offset
) { fFromTarget
.offset
= offset
; }
118 virtual const char* getDescription() const;
119 virtual uint64_t getFromTargetOffset() const { return fFromTarget
.offset
; }
120 virtual bool isBranch() const;
121 virtual const char* getTargetDisplayName() const { return (fToTarget
.atom
!= NULL
) ? fToTarget
.atom
->getDisplayName() : fToTargetName
; }
122 virtual const char* getFromTargetDisplayName() const { return (fFromTarget
.atom
!= NULL
) ? fFromTarget
.atom
->getDisplayName() : fFromTargetName
; }
124 static bool fgForFinalLinkedImage
;
127 pint_t fFixUpOffsetInSrc
;
128 AtomAndOffset fToTarget
;
129 AtomAndOffset fFromTarget
;
130 const char* fToTargetName
;
131 const char* fFromTargetName
;
137 template <typename A
> bool Reference
<A
>::fgForFinalLinkedImage
= true;
139 template <typename A
>
140 Reference
<A
>::Reference(Kinds kind
, const AtomAndOffset
& at
, const AtomAndOffset
& toTarget
)
141 : fFixUpOffsetInSrc(at
.offset
), fToTarget(toTarget
), fToTargetName(NULL
), fFromTargetName(NULL
),
144 // make reference a by-name unless:
145 // - the reference type is only used with direct references
146 // - the target is translation unit scoped
147 // - the target kind is not regular (is weak or tentative)
148 if ( (kind
!= A::kNoFixUp
) && (kind
!= A::kFollowOn
) && (kind
!= A::kGroupSubordinate
)
149 && (toTarget
.atom
->getScope() != ObjectFile::Atom::scopeTranslationUnit
)
150 && (toTarget
.atom
->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition
)
151 && (toTarget
.atom
!= at
.atom
) ) {
152 fToTargetName
= toTarget
.atom
->getName();
153 //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());
154 fToTarget
.atom
= NULL
;
156 ((class BaseAtom
*)at
.atom
)->addReference(this);
157 //fprintf(stderr, "Reference(): %p fToTarget<%s, %08X>\n", this, (fToTarget.atom != NULL) ? fToTarget.atom->getDisplayName() : fToTargetName , fToTarget.offset);
160 template <typename A
>
161 Reference
<A
>::Reference(Kinds kind
, const AtomAndOffset
& at
, const AtomAndOffset
& fromTarget
, const AtomAndOffset
& toTarget
)
162 : fFixUpOffsetInSrc(at
.offset
), fToTarget(toTarget
), fFromTarget(fromTarget
),
163 fToTargetName(NULL
), fFromTargetName(NULL
), fKind(kind
)
165 // make reference a by-name where needed
166 if ( (kind
!= A::kNoFixUp
) && (kind
!= A::kFollowOn
) && (kind
!= A::kGroupSubordinate
)
167 && (toTarget
.atom
->getScope() != ObjectFile::Atom::scopeTranslationUnit
)
168 && (toTarget
.atom
->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition
)
169 && (toTarget
.atom
!= at
.atom
) ) {
170 fToTargetName
= toTarget
.atom
->getName();
171 fToTarget
.atom
= NULL
;
173 ((class BaseAtom
*)at
.atom
)->addReference(this);
174 //fprintf(stderr, "Reference(): %p kind=%d, fToTarget<%s, %08X>, fromTarget<%s, %08X>\n", this, kind,
175 // this->getTargetName(), fToTarget.offset, this->getFromTargetName(), fromTarget.offset);
178 template <typename A
>
179 Reference
<A
>::Reference(Kinds kind
, const AtomAndOffset
& at
, const char* toName
, uint32_t toOffset
)
180 : fFixUpOffsetInSrc(at
.offset
),
181 fToTargetName(toName
), fFromTargetName(NULL
), fKind(kind
)
183 fToTarget
.offset
= toOffset
;
184 ((class BaseAtom
*)at
.atom
)->addReference(this);
187 template <typename A
>
188 ObjectFile::Reference::TargetBinding Reference
<A
>::getTargetBinding() const
190 if ( fgForFinalLinkedImage
) {
191 if ( (fKind
== A::kDtraceProbe
) || (fKind
== A::kDtraceProbeSite
) || (fKind
== A::kDtraceIsEnabledSite
) || (fKind
== A::kDtraceTypeReference
) )
192 return ObjectFile::Reference::kDontBind
;
194 if ( fToTarget
.atom
== NULL
)
195 return ObjectFile::Reference::kUnboundByName
;
196 if ( fToTargetName
== NULL
)
197 return ObjectFile::Reference::kBoundDirectly
;
199 return ObjectFile::Reference::kBoundByName
;
202 template <typename A
>
203 ObjectFile::Reference::TargetBinding Reference
<A
>::getFromTargetBinding() const
205 if ( fFromTarget
.atom
== NULL
) {
206 if ( fFromTargetName
== NULL
)
207 return ObjectFile::Reference::kDontBind
;
209 return ObjectFile::Reference::kUnboundByName
;
212 if ( fFromTargetName
== NULL
)
213 return ObjectFile::Reference::kBoundDirectly
;
215 return ObjectFile::Reference::kBoundByName
;
221 template <typename A
>
222 class Segment
: public ObjectFile::Segment
225 Segment(const macho_section
<typename
A::P
>* sect
);
226 virtual const char* getName() const { return fSection
->segname(); }
227 virtual bool isContentReadable() const { return true; }
228 virtual bool isContentWritable() const { return fWritable
; }
229 virtual bool isContentExecutable() const { return fExecutable
; }
231 const macho_section
<typename
A::P
>* fSection
;
236 template <typename A
>
237 Segment
<A
>::Segment(const macho_section
<typename
A::P
>* sect
)
238 : fSection(sect
), fWritable(true), fExecutable(false)
240 if ( strcmp(fSection
->segname(), "__TEXT") == 0 ) {
244 else if ( strcmp(fSection
->segname(), "__IMPORT") == 0 ) {
251 class DataSegment
: public ObjectFile::Segment
254 virtual const char* getName() const { return "__DATA"; }
255 virtual bool isContentReadable() const { return true; }
256 virtual bool isContentWritable() const { return true; }
257 virtual bool isContentExecutable() const { return false; }
259 static DataSegment fgSingleton
;
262 DataSegment
DataSegment::fgSingleton
;
264 class LinkEditSegment
: public ObjectFile::Segment
267 virtual const char* getName() const { return "__LINKEDIT"; }
268 virtual bool isContentReadable() const { return true; }
269 virtual bool isContentWritable() const { return false; }
270 virtual bool isContentExecutable() const { return false; }
272 static LinkEditSegment fgSingleton
;
275 LinkEditSegment
LinkEditSegment::fgSingleton
;
277 class BaseAtom
: public ObjectFile::Atom
280 BaseAtom() : fStabsStartIndex(0), fStabsCount(0), fHasCompactUnwindInfo(false) {}
282 virtual void setSize(uint64_t size
) = 0;
283 virtual void addReference(ObjectFile::Reference
* ref
) = 0;
284 virtual void sortReferences() = 0;
285 virtual void addLineInfo(const ObjectFile::LineInfo
& info
) = 0;
286 virtual const ObjectFile::ReaderOptions
& getOptions() const = 0;
287 virtual uint64_t getObjectAddress() const = 0;
288 virtual uint32_t getOrdinal() const { return fOrdinal
; }
289 virtual void setOrdinal(uint32_t value
) { fOrdinal
= value
; }
290 virtual const void* getSectionRecord() const = 0;
291 virtual unsigned int getSectionIndex() const = 0;
292 virtual bool isAlias() const { return false; }
293 virtual uint8_t getLSDAReferenceKind() const { return 0; }
294 virtual uint8_t getPersonalityReferenceKind() const { return 0; }
295 virtual uint32_t getCompactUnwindEncoding(uint64_t ehAtomAddress
) { return 0; }
296 virtual ObjectFile::UnwindInfo::iterator
beginUnwind() { return fHasCompactUnwindInfo
? &fSingleUnwindInfo
[0] : NULL
; }
297 virtual ObjectFile::UnwindInfo::iterator
endUnwind() { return fHasCompactUnwindInfo
? &fSingleUnwindInfo
[1] : NULL
; }
298 virtual ObjectFile::Reference
* getLSDA();
299 virtual ObjectFile::Reference
* getFDE();
300 virtual Atom
* getPersonalityPointer();
301 virtual void setCompactUnwindEncoding(uint64_t ehAtomAddress
);
303 uint32_t fStabsStartIndex
;
304 uint32_t fStabsCount
;
306 ObjectFile::UnwindInfo fSingleUnwindInfo
[1];
307 bool fHasCompactUnwindInfo
;
311 ObjectFile::Reference
* BaseAtom::getLSDA()
313 const uint8_t groupKind
= this->getLSDAReferenceKind();
314 const std::vector
<ObjectFile::Reference
*>& refs
= this->getReferences();
315 for (std::vector
<ObjectFile::Reference
*>::const_iterator it
=refs
.begin(); it
!= refs
.end(); it
++) {
316 ObjectFile::Reference
* ref
= *it
;
317 if ( (ref
->getKind() == groupKind
) && (ref
->getTarget().getContentType() == ObjectFile::Atom::kLSDAType
) ) {
324 ObjectFile::Reference
* BaseAtom::getFDE()
326 const uint8_t groupKind
= this->getLSDAReferenceKind();
327 const std::vector
<ObjectFile::Reference
*>& refs
= this->getReferences();
328 for (std::vector
<ObjectFile::Reference
*>::const_iterator it
=refs
.begin(); it
!= refs
.end(); it
++) {
329 ObjectFile::Reference
* ref
= *it
;
330 if ( (ref
->getKind() == groupKind
) && (ref
->getTarget().getContentType() == ObjectFile::Atom::kCFIType
) ) {
337 ObjectFile::Atom
* BaseAtom::getPersonalityPointer()
339 const uint8_t personalityKind
= this->getPersonalityReferenceKind();
340 const std::vector
<ObjectFile::Reference
*>& refs
= this->getReferences();
341 for (std::vector
<ObjectFile::Reference
*>::const_iterator it
=refs
.begin(); it
!= refs
.end(); it
++) {
342 ObjectFile::Reference
* ref
= *it
;
343 if ( ref
->getKind() == personalityKind
) {
344 if ( strcmp(ref
->getTarget().getSectionName(), "__nl_symbol_ptr") == 0 )
345 return &ref
->getTarget();
346 if ( strcmp(ref
->getTarget().getSectionName(), "__pointers") == 0 )
347 return &ref
->getTarget();
354 void BaseAtom::setCompactUnwindEncoding(uint64_t ehAtomAddress
)
356 fSingleUnwindInfo
[0].unwindInfo
= this->getCompactUnwindEncoding(ehAtomAddress
);
357 fHasCompactUnwindInfo
= true;
364 bool operator()(const class BaseAtom
* left
, const class BaseAtom
* right
) {
367 uint64_t leftAddr
= left
->getObjectAddress();
368 uint64_t rightAddr
= right
->getObjectAddress();
369 if ( leftAddr
< rightAddr
) {
372 else if ( leftAddr
> rightAddr
) {
376 // if they have same address, one might be the end of a section and the other the start of the next section
377 const void* leftSection
= left
->getSectionRecord();
378 const void* rightSection
= right
->getSectionRecord();
379 if ( leftSection
!= rightSection
) {
380 return ( leftSection
< rightSection
);
382 // if they have same address and section, one might be an alias
383 bool leftAlias
= left
->isAlias();
384 bool rightAlias
= right
->isAlias();
385 if ( leftAlias
&& rightAlias
) {
386 // sort multiple aliases for same address first by scope
387 ObjectFile::Atom::Scope leftScope
= left
->getScope();
388 ObjectFile::Atom::Scope rightScope
= right
->getScope();
389 if ( leftScope
!= rightScope
) {
390 return ( leftScope
< rightScope
);
392 // sort multiple aliases for same address then by name
393 return ( strcmp(left
->getName(), right
->getName()) < 0 );
395 else if ( leftAlias
) {
398 else if ( rightAlias
) {
401 // one might be a section start or end label
402 switch ( left
->getContentType() ) {
403 case ObjectFile::Atom::kSectionStart
:
405 case ObjectFile::Atom::kSectionEnd
:
410 switch ( right
->getContentType() ) {
411 case ObjectFile::Atom::kSectionStart
:
413 case ObjectFile::Atom::kSectionEnd
:
418 // they could be tentative defintions
419 switch ( left
->getDefinitionKind() ) {
420 case ObjectFile::Atom::kTentativeDefinition
:
421 // sort tentative definitions by name
422 return ( strcmp(left
->getName(), right
->getName()) < 0 );
423 case ObjectFile::Atom::kAbsoluteSymbol
:
424 // sort absolute symbols with same address by name
425 return ( strcmp(left
->getName(), right
->getName()) < 0 );
427 // hack for rdar://problem/5102873
428 if ( !left
->isZeroFill() || !right
->isZeroFill() )
429 warning("atom sorting error for %s and %s in %s", left
->getDisplayName(), right
->getDisplayName(), left
->getFile()->getPath());
439 // A SymbolAtom represents a chunk of a mach-o object file that has a symbol table entry
440 // pointing to it. A C function or global variable is represented by one of these atoms.
443 template <typename A
>
444 class SymbolAtom
: public BaseAtom
447 virtual ObjectFile::Reader
* getFile() const { return &fOwner
; }
448 virtual bool getTranslationUnitSource(const char** dir
, const char** name
) const
449 { return fOwner
.getTranslationUnitSource(dir
, name
); }
450 virtual const char* getName() const { return &fOwner
.fStrings
[fSymbol
->n_strx()]; }
451 virtual const char* getDisplayName() const { return getName(); }
452 virtual ObjectFile::Atom::Scope
getScope() const { return fScope
; }
453 virtual ObjectFile::Atom::DefinitionKind
getDefinitionKind() const { return ((fSymbol
->n_desc() & N_WEAK_DEF
) != 0)
454 ? ObjectFile::Atom::kWeakDefinition
: ObjectFile::Atom::kRegularDefinition
; }
455 virtual ObjectFile::Atom::ContentType
getContentType() const { return fType
; }
456 virtual SymbolTableInclusion
getSymbolTableInclusion() const { return fSymbolTableInclusion
; }
457 virtual bool dontDeadStrip() const;
458 virtual bool isZeroFill() const;
459 virtual bool isThumb() const { return ((fSymbol
->n_desc() & N_ARM_THUMB_DEF
) != 0); }
460 virtual uint64_t getSize() const { return fSize
; }
461 virtual std::vector
<ObjectFile::Reference
*>& getReferences() const { return (std::vector
<ObjectFile::Reference
*>&)(fReferences
); }
462 virtual bool mustRemainInSection() const { return true; }
463 virtual const char* getSectionName() const;
464 virtual Segment
<A
>& getSegment() const { return *fSegment
; }
465 virtual ObjectFile::Atom
& getFollowOnAtom() const;
466 virtual std::vector
<ObjectFile::LineInfo
>* getLineInfo() const { return (std::vector
<ObjectFile::LineInfo
>*)&fLineInfo
; }
467 virtual ObjectFile::Alignment
getAlignment() const { return fAlignment
; }
468 virtual void copyRawContent(uint8_t buffer
[]) const;
469 virtual void setScope(ObjectFile::Atom::Scope newScope
) { fScope
= newScope
; }
470 virtual void setSize(uint64_t size
);
471 virtual void addReference(ObjectFile::Reference
* ref
) { fReferences
.push_back((Reference
<A
>*)ref
); }
472 virtual void sortReferences() { std::sort(fReferences
.begin(), fReferences
.end(), ReferenceSorter()); }
473 virtual void addLineInfo(const ObjectFile::LineInfo
& info
) { fLineInfo
.push_back(info
); }
474 virtual const ObjectFile::ReaderOptions
& getOptions() const { return fOwner
.fOptions
; }
475 virtual uint64_t getObjectAddress() const { return fAddress
; }
476 virtual const void* getSectionRecord() const { return (const void*)fSection
; }
477 virtual unsigned int getSectionIndex() const { return 1 + (fSection
- fOwner
.fSectionsStart
); }
478 virtual uint8_t getLSDAReferenceKind() const;
479 virtual uint8_t getPersonalityReferenceKind() const;
480 virtual uint32_t getCompactUnwindEncoding(uint64_t ehAtomAddress
);
483 typedef typename
A::P P
;
484 typedef typename
A::P::E E
;
485 typedef typename
A::P::uint_t pint_t
;
486 typedef typename
A::ReferenceKinds Kinds
;
487 typedef typename
std::vector
<Reference
<A
>*> ReferenceVector
;
488 typedef typename
ReferenceVector::iterator ReferenceVectorIterator
; // seems to help C++ parser
489 typedef typename
ReferenceVector::const_iterator ReferenceVectorConstIterator
; // seems to help C++ parser
490 friend class Reader
<A
>;
492 SymbolAtom(Reader
<A
>&, const macho_nlist
<P
>*, const macho_section
<P
>*);
493 virtual ~SymbolAtom() {}
496 const macho_nlist
<P
>* fSymbol
;
499 const macho_section
<P
>* fSection
;
500 Segment
<A
>* fSegment
;
501 ReferenceVector fReferences
;
502 std::vector
<ObjectFile::LineInfo
> fLineInfo
;
503 ObjectFile::Atom::Scope fScope
;
504 SymbolTableInclusion fSymbolTableInclusion
;
505 ObjectFile::Atom::ContentType fType
;
506 ObjectFile::Alignment fAlignment
;
510 template <typename A
>
511 SymbolAtom
<A
>::SymbolAtom(Reader
<A
>& owner
, const macho_nlist
<P
>* symbol
, const macho_section
<P
>* section
)
512 : fOwner(owner
), fSymbol(symbol
), fAddress(0), fSize(0), fSection(section
), fSegment(NULL
), fType(ObjectFile::Atom::kUnclassifiedType
), fAlignment(0)
514 fSingleUnwindInfo
[0].startOffset
= 0;
515 fSingleUnwindInfo
[0].unwindInfo
= 0;
516 uint8_t type
= symbol
->n_type();
517 if ( (type
& N_EXT
) == 0 )
518 fScope
= ObjectFile::Atom::scopeTranslationUnit
;
519 else if ( (type
& N_PEXT
) != 0 )
520 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
522 fScope
= ObjectFile::Atom::scopeGlobal
;
523 if ( (type
& N_TYPE
) == N_SECT
) {
525 fSegment
= new Segment
<A
>(fSection
);
526 fAddress
= fSymbol
->n_value();
527 pint_t sectionStartAddr
= section
->addr();
528 pint_t sectionEndAddr
= section
->addr()+section
->size();
529 if ( (fAddress
< sectionStartAddr
) || (fAddress
> (sectionEndAddr
)) ) {
530 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",
531 this->getName(), (uint64_t)fAddress
, fSymbol
->n_sect(), section
->segname(), section
->sectname(),
532 (uint64_t)sectionStartAddr
, (uint64_t)(sectionEndAddr
) );
536 warning("unknown symbol type: %d", type
);
539 //fprintf(stderr, "SymbolAtom(%p) %s fAddress=0x%X\n", this, this->getDisplayName(), (uint32_t)fAddress);
540 // support for .o files built with old ld64
541 if ( (fSymbol
->n_desc() & N_WEAK_DEF
) && (strcmp(fSection
->sectname(),"__picsymbolstub1__TEXT") == 0) ) {
542 const char* name
= this->getName();
543 const int nameLen
= strlen(name
);
544 if ( (nameLen
> 6) && strcmp(&name
[nameLen
-5], "$stub") == 0 ) {
545 // switch symbol to point at name that does not have trailing $stub
546 char correctName
[nameLen
];
547 strncpy(correctName
, name
, nameLen
-5);
548 correctName
[nameLen
-5] = '\0';
549 const macho_nlist
<P
>* symbolsStart
= fOwner
.fSymbols
;
550 const macho_nlist
<P
>* symbolsEnd
= &symbolsStart
[fOwner
.fSymbolCount
];
551 for(const macho_nlist
<P
>* s
= symbolsStart
; s
< symbolsEnd
; ++s
) {
552 if ( strcmp(&fOwner
.fStrings
[s
->n_strx()], correctName
) == 0 ) {
559 // support for labeled stubs
560 switch ( section
->flags() & SECTION_TYPE
) {
562 setSize(section
->reserved2());
564 case S_LAZY_SYMBOL_POINTERS
:
565 case S_NON_LAZY_SYMBOL_POINTERS
:
566 setSize(sizeof(pint_t
));
568 case S_4BYTE_LITERALS
:
571 case S_8BYTE_LITERALS
:
574 case S_16BYTE_LITERALS
:
577 case S_CSTRING_LITERALS
:
578 setSize(strlen((char*)(fOwner
.fHeader
) + section
->offset() + fAddress
- section
->addr()) + 1);
579 fType
= ObjectFile::Atom::kCStringType
;
584 // size calculate later after next atom is found
589 fAlignment
= ObjectFile::Alignment(fSection
->align(), fAddress
% (1 << fSection
->align()));
591 // compute whether this atom needs to be in symbol table
592 if ( (fSymbol
->n_desc() & REFERENCED_DYNAMICALLY
) != 0) {
593 fSymbolTableInclusion
= ObjectFile::Atom::kSymbolTableInAndNeverStrip
;
595 else if ( fOwner
.fOptions
.fForFinalLinkedImage
&& !fOwner
.fOptions
.fForStatic
&& (fOwner
.fStrings
[fSymbol
->n_strx()] == 'l') ) {
596 // labels beginning with a lowercase ell are automatically removed in final linked images <rdar://problem/4571042>
597 // xnu code base uses a lot of asesembly labels that start with 'l', don't strip those (static executable)
598 fSymbolTableInclusion
= ObjectFile::Atom::kSymbolTableNotIn
;
601 fSymbolTableInclusion
= ObjectFile::Atom::kSymbolTableIn
;
604 // work around malformed icc generated .o files <rdar://problem/5349847>
605 // if section starts with a symbol and that symbol address does not match section alignment, then force it to
606 if ( (section
->addr() == fAddress
) && (fAlignment
.modulus
!= 0) )
607 fAlignment
.modulus
= 0;
611 template <typename A
>
612 bool SymbolAtom
<A
>::dontDeadStrip() const
614 // the symbol can have a no-dead-strip bit
615 if ( (fSymbol
->n_desc() & (N_NO_DEAD_STRIP
|REFERENCED_DYNAMICALLY
)) != 0 )
617 // or the section can have a no-dead-strip bit
618 return ( fSection
->flags() & S_ATTR_NO_DEAD_STRIP
);
622 template <typename A
>
623 const char* SymbolAtom
<A
>::getSectionName() const
625 if ( fOwner
.fOptions
.fForFinalLinkedImage
) {
626 if ( strcmp(fSection
->sectname(), "__textcoal_nt") == 0 )
628 else if ( strcmp(fSection
->sectname(), "__const_coal") == 0 )
630 else if ( strcmp(fSection
->sectname(), "__datacoal_nt") == 0 )
632 else if ( fOwner
.fOptions
.fAutoOrderInitializers
&& (strcmp(fSection
->sectname(), "__StaticInit") == 0) )
635 switch ( fSection
->flags() & SECTION_TYPE
) {
636 case S_4BYTE_LITERALS
:
637 case S_8BYTE_LITERALS
:
638 case S_16BYTE_LITERALS
:
644 if ( strlen(fSection
->sectname()) > 15 ) {
645 static char temp
[18];
646 strncpy(temp
, fSection
->sectname(), 16);
650 return fSection
->sectname();
653 template <typename A
>
654 ObjectFile::Atom
& SymbolAtom
<A
>::getFollowOnAtom() const
656 for (ReferenceVectorConstIterator it
=fReferences
.begin(); it
!= fReferences
.end(); it
++) {
657 Reference
<A
>* ref
= *it
;
658 if ( ref
->getKind() == A::kFollowOn
)
659 return ref
->getTarget();
661 return *((ObjectFile::Atom
*)NULL
);
664 template <typename A
>
665 bool SymbolAtom
<A
>::isZeroFill() const
667 return ( ((fSection
->flags() & SECTION_TYPE
) == S_ZEROFILL
) && fOwner
.fOptions
.fOptimizeZeroFill
);
674 Beyond(uint64_t offset
) : fOffset(offset
) {}
675 bool operator()(ObjectFile::Reference
* ref
) const {
676 return ( ref
->getFixUpOffset() >= fOffset
);
683 template <typename A
>
684 void SymbolAtom
<A
>::setSize(uint64_t size
)
686 // when resizing, any references beyond the new size are tossed
687 if ( (fSize
!= 0) && (fReferences
.size() > 0) )
688 fReferences
.erase(std::remove_if(fReferences
.begin(), fReferences
.end(), Beyond(size
)), fReferences
.end());
693 template <typename A
>
694 void SymbolAtom
<A
>::copyRawContent(uint8_t buffer
[]) const
698 bzero(buffer
, fSize
);
700 uint32_t fileOffset
= fSection
->offset() - fSection
->addr() + fAddress
;
701 memcpy(buffer
, (char*)(fOwner
.fHeader
)+fileOffset
, fSize
);
709 // A SymbolAliasAtom represents an alternate name for a SymbolAtom
712 template <typename A
>
713 class SymbolAliasAtom
: public BaseAtom
716 virtual ObjectFile::Reader
* getFile() const { return fAliasOf
.getFile(); }
717 virtual bool getTranslationUnitSource(const char** dir
, const char** name
) const
718 { return fAliasOf
.getTranslationUnitSource(dir
, name
); }
719 virtual const char* getName() const { return fName
; }
720 virtual const char* getDisplayName() const { return fName
; }
721 virtual ObjectFile::Atom::Scope
getScope() const { return fScope
; }
722 virtual ObjectFile::Atom::DefinitionKind
getDefinitionKind() const { return fAliasOf
.getDefinitionKind(); }
723 virtual SymbolTableInclusion
getSymbolTableInclusion() const { return fAliasOf
.getSymbolTableInclusion(); }
724 virtual bool dontDeadStrip() const { return fDontDeadStrip
; }
725 virtual bool isZeroFill() const { return fAliasOf
.isZeroFill(); }
726 virtual bool isThumb() const { return fAliasOf
.isThumb(); }
727 virtual uint64_t getSize() const { return 0; }
728 virtual std::vector
<ObjectFile::Reference
*>& getReferences() const { return (std::vector
<ObjectFile::Reference
*>&)(fReferences
); }
729 virtual bool mustRemainInSection() const { return true; }
730 virtual const char* getSectionName() const { return fAliasOf
.getSectionName(); }
731 virtual Segment
<A
>& getSegment() const { return (Segment
<A
>&)fAliasOf
.getSegment(); }
732 virtual ObjectFile::Atom
& getFollowOnAtom() const { return (ObjectFile::Atom
&)fAliasOf
; }
733 virtual std::vector
<ObjectFile::LineInfo
>* getLineInfo() const { return NULL
; }
734 virtual ObjectFile::Alignment
getAlignment() const { return fAliasOf
.getAlignment(); }
735 virtual void copyRawContent(uint8_t buffer
[]) const {}
736 virtual void setScope(ObjectFile::Atom::Scope newScope
) { fScope
= newScope
; }
737 virtual void setSize(uint64_t size
) { }
738 virtual void addReference(ObjectFile::Reference
* ref
) { fReferences
.push_back((Reference
<A
>*)ref
); }
739 virtual void sortReferences() { std::sort(fReferences
.begin(), fReferences
.end(), ReferenceSorter()); }
740 virtual void addLineInfo(const ObjectFile::LineInfo
& info
) { }
741 virtual const ObjectFile::ReaderOptions
& getOptions() const { return fAliasOf
.getOptions(); }
742 virtual uint64_t getObjectAddress() const { return fAliasOf
.getObjectAddress(); }
743 virtual const void* getSectionRecord() const { return fAliasOf
.getSectionRecord(); }
744 virtual unsigned int getSectionIndex() const { return fAliasOf
.getSectionIndex(); }
745 virtual bool isAlias() const { return true; }
748 typedef typename
A::P P
;
749 typedef typename
std::vector
<Reference
<A
>*> ReferenceVector
;
750 typedef typename
ReferenceVector::iterator ReferenceVectorIterator
; // seems to help C++ parser
751 typedef typename
ReferenceVector::const_iterator ReferenceVectorConstIterator
; // seems to help C++ parser
752 friend class Reader
<A
>;
754 SymbolAliasAtom(const char* name
, const macho_nlist
<P
>*, const BaseAtom
& );
755 virtual ~SymbolAliasAtom() {}
758 const BaseAtom
& fAliasOf
;
759 ObjectFile::Atom::Scope fScope
;
761 ReferenceVector fReferences
;
765 template <typename A
>
766 SymbolAliasAtom
<A
>::SymbolAliasAtom(const char* name
, const macho_nlist
<P
>* symbol
, const BaseAtom
& aliasOf
)
767 : fName(name
), fAliasOf(aliasOf
)
769 //fprintf(stderr, "SymbolAliasAtom(%p) %s\n", this, name);
770 if ( symbol
!= NULL
) {
771 uint8_t type
= symbol
->n_type();
772 if ( (type
& N_EXT
) == 0 )
773 fScope
= ObjectFile::Atom::scopeTranslationUnit
;
774 else if ( (type
& N_PEXT
) != 0 )
775 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
777 fScope
= ObjectFile::Atom::scopeGlobal
;
778 fDontDeadStrip
= ((symbol
->n_desc() & (N_NO_DEAD_STRIP
|REFERENCED_DYNAMICALLY
)) != 0);
781 // aliases defined on the command line are initially global scope
782 fScope
= ObjectFile::Atom::scopeGlobal
;
783 fDontDeadStrip
= false;
785 // add follow-on reference to real atom
786 new Reference
<A
>(A::kFollowOn
, AtomAndOffset(this), AtomAndOffset((ObjectFile::Atom
*)&aliasOf
));
791 // A TentativeAtom represents a C "common" or "tentative" defintion of data.
792 // For instance, "int foo;" is neither a declaration or a definition and
793 // is represented by a TentativeAtom.
795 template <typename A
>
796 class TentativeAtom
: public BaseAtom
799 virtual ObjectFile::Reader
* getFile() const { return &fOwner
; }
800 virtual bool getTranslationUnitSource(const char** dir
, const char** name
) const
801 { return fOwner
.getTranslationUnitSource(dir
, name
); }
802 virtual const char* getName() const { return &fOwner
.fStrings
[fSymbol
->n_strx()]; }
803 virtual const char* getDisplayName() const { return getName(); }
804 virtual ObjectFile::Atom::Scope
getScope() const { return fScope
; }
805 virtual ObjectFile::Atom::DefinitionKind
getDefinitionKind() const { return ObjectFile::Atom::kTentativeDefinition
; }
806 virtual bool isZeroFill() const { return fOwner
.fOptions
.fOptimizeZeroFill
; }
807 virtual bool isThumb() const { return false; }
808 virtual SymbolTableInclusion
getSymbolTableInclusion() const { return ((fSymbol
->n_desc() & REFERENCED_DYNAMICALLY
) != 0)
809 ? ObjectFile::Atom::kSymbolTableInAndNeverStrip
: ObjectFile::Atom::kSymbolTableIn
; }
810 virtual bool dontDeadStrip() const { return ((fSymbol
->n_desc() & (N_NO_DEAD_STRIP
|REFERENCED_DYNAMICALLY
)) != 0); }
811 virtual uint64_t getSize() const { return fSymbol
->n_value(); }
812 virtual std::vector
<ObjectFile::Reference
*>& getReferences() const { return fgNoReferences
; }
813 virtual bool mustRemainInSection() const { return true; }
814 virtual const char* getSectionName() const;
815 virtual ObjectFile::Segment
& getSegment() const { return DataSegment::fgSingleton
; }
816 virtual ObjectFile::Atom
& getFollowOnAtom() const { return *(ObjectFile::Atom
*)NULL
; }
817 virtual std::vector
<ObjectFile::LineInfo
>* getLineInfo() const { return NULL
; }
818 virtual ObjectFile::Alignment
getAlignment() const;
819 virtual void copyRawContent(uint8_t buffer
[]) const;
820 virtual void setScope(ObjectFile::Atom::Scope newScope
) { fScope
= newScope
; }
821 virtual void setSize(uint64_t size
) { }
822 virtual void addReference(ObjectFile::Reference
* ref
) { throw "ld: can't add references"; }
823 virtual void sortReferences() { }
824 virtual void addLineInfo(const ObjectFile::LineInfo
& info
) { throw "ld: can't add line info to tentative definition"; }
825 virtual const ObjectFile::ReaderOptions
& getOptions() const { return fOwner
.fOptions
; }
826 virtual uint64_t getObjectAddress() const { return ULLONG_MAX
; }
827 virtual const void* getSectionRecord() const { return NULL
; }
828 virtual unsigned int getSectionIndex() const { return 0; }
831 typedef typename
A::P P
;
832 typedef typename
A::P::E E
;
833 typedef typename
A::P::uint_t pint_t
;
834 typedef typename
A::ReferenceKinds Kinds
;
835 friend class Reader
<A
>;
837 TentativeAtom(Reader
<A
>&, const macho_nlist
<P
>*);
838 virtual ~TentativeAtom() {}
841 const macho_nlist
<P
>* fSymbol
;
842 ObjectFile::Atom::Scope fScope
;
843 static std::vector
<ObjectFile::Reference
*> fgNoReferences
;
846 template <typename A
>
847 std::vector
<ObjectFile::Reference
*> TentativeAtom
<A
>::fgNoReferences
;
849 template <typename A
>
850 TentativeAtom
<A
>::TentativeAtom(Reader
<A
>& owner
, const macho_nlist
<P
>* symbol
)
851 : fOwner(owner
), fSymbol(symbol
)
853 uint8_t type
= symbol
->n_type();
854 if ( (type
& N_EXT
) == 0 )
855 fScope
= ObjectFile::Atom::scopeTranslationUnit
;
856 else if ( (type
& N_PEXT
) != 0 )
857 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
859 fScope
= ObjectFile::Atom::scopeGlobal
;
860 if ( ((type
& N_TYPE
) == N_UNDF
) && (symbol
->n_value() != 0) ) {
861 // tentative definition
864 warning("unknown symbol type: %d", type
);
866 //fprintf(stderr, "TentativeAtom(%p) %s\n", this, this->getDisplayName());
870 template <typename A
>
871 ObjectFile::Alignment TentativeAtom
<A
>::getAlignment() const
873 uint8_t alignment
= GET_COMM_ALIGN(fSymbol
->n_desc());
874 if ( alignment
== 0 ) {
875 // common symbols align to their size
876 // that is, a 4-byte common aligns to 4-bytes
877 // if this size is not a power of two,
878 // then round up to the next power of two
879 uint64_t size
= this->getSize();
880 alignment
= 63 - (uint8_t)__builtin_clzll(size
);
881 if ( size
!= (1ULL << alignment
) )
884 // limit alignment of extremely large commons to 2^15 bytes (8-page)
885 if ( alignment
< 12 )
886 return ObjectFile::Alignment(alignment
);
888 return ObjectFile::Alignment(12);
891 template <typename A
>
892 const char* TentativeAtom
<A
>::getSectionName() const
894 if ( fOwner
.fOptions
.fForFinalLinkedImage
|| fOwner
.fOptions
.fMakeTentativeDefinitionsReal
)
901 template <typename A
>
902 void TentativeAtom
<A
>::copyRawContent(uint8_t buffer
[]) const
904 bzero(buffer
, getSize());
909 // An AnonymousAtom represents compiler generated data that has no name.
910 // For instance, a literal C-string or a 64-bit floating point constant
911 // is represented by an AnonymousAtom.
913 template <typename A
>
914 class AnonymousAtom
: public BaseAtom
917 virtual ObjectFile::Reader
* getFile() const { return &fOwner
; }
918 virtual bool getTranslationUnitSource(const char** dir
, const char** name
) const { return false; }
919 virtual const char* getName() const { return fSynthesizedName
; }
920 virtual const char* getDisplayName() const;
921 virtual ObjectFile::Atom::Scope
getScope() const;
922 virtual ObjectFile::Atom::DefinitionKind
getDefinitionKind() const { return fKind
; }
923 virtual ObjectFile::Atom::ContentType
getContentType() const { return fType
; }
924 virtual ObjectFile::Atom::SymbolTableInclusion
getSymbolTableInclusion() const { return fSymbolTableInclusion
; }
925 virtual bool dontDeadStrip() const { return fDontDeadStrip
; }
926 virtual bool isZeroFill() const;
927 virtual bool isThumb() const { return false; }
928 virtual uint64_t getSize() const { return fSize
; }
929 virtual std::vector
<ObjectFile::Reference
*>& getReferences() const { return (std::vector
<ObjectFile::Reference
*>&)(fReferences
); }
930 virtual bool mustRemainInSection() const { return true; }
931 virtual const char* getSectionName() const;
932 virtual Segment
<A
>& getSegment() const { return *fSegment
; }
933 virtual ObjectFile::Atom
& getFollowOnAtom() const;
934 virtual std::vector
<ObjectFile::LineInfo
>* getLineInfo() const { return NULL
; }
935 virtual ObjectFile::Alignment
getAlignment() const;
936 virtual void copyRawContent(uint8_t buffer
[]) const;
937 virtual void setScope(ObjectFile::Atom::Scope newScope
) { fScope
= newScope
; }
938 virtual void setSize(uint64_t size
) { fSize
= size
; }
939 virtual void addReference(ObjectFile::Reference
* ref
) { fReferences
.push_back((Reference
<A
>*)ref
); }
940 virtual void sortReferences() { std::sort(fReferences
.begin(), fReferences
.end(), ReferenceSorter()); }
941 virtual void addLineInfo(const ObjectFile::LineInfo
& info
);
942 virtual const ObjectFile::ReaderOptions
& getOptions() const { return fOwner
.fOptions
; }
943 virtual uint64_t getObjectAddress() const { return fAddress
; }
944 virtual const void* getSectionRecord() const { return (const void*)fSection
; }
945 virtual unsigned int getSectionIndex() const { return fSectionIndex
; }
946 BaseAtom
* redirectTo() { return fRedirect
; }
947 bool isWeakImportStub() { return fWeakImportStub
; }
949 virtual uint8_t getLSDAReferenceKind() const;
950 virtual uint8_t getPersonalityReferenceKind() const;
951 virtual uint32_t getCompactUnwindEncoding(uint64_t ehAtomAddress
);
954 typedef typename
A::P P
;
955 typedef typename
A::P::E E
;
956 typedef typename
A::P::uint_t pint_t
;
957 typedef typename
A::ReferenceKinds Kinds
;
958 typedef typename
std::vector
<Reference
<A
>*> ReferenceVector
;
959 typedef typename
ReferenceVector::iterator ReferenceVectorIterator
; // seems to help C++ parser
960 typedef typename
ReferenceVector::const_iterator ReferenceVectorConstIterator
; // seems to help C++ parser
961 friend class Reader
<A
>;
963 AnonymousAtom(Reader
<A
>&, const macho_section
<P
>*, pint_t addr
, pint_t size
);
964 virtual ~AnonymousAtom() {}
965 static bool cstringsHaveLabels();
968 const char* fSynthesizedName
;
969 const char* fDisplayName
;
970 const macho_section
<P
>* fSection
;
973 Segment
<A
>* fSegment
;
974 ReferenceVector fReferences
;
977 bool fWeakImportStub
;
978 ObjectFile::Atom::SymbolTableInclusion fSymbolTableInclusion
;
979 ObjectFile::Atom::Scope fScope
;
980 ObjectFile::Atom::DefinitionKind fKind
;
981 ObjectFile::Atom::ContentType fType
;
982 unsigned int fSectionIndex
;
985 template <typename A
>
986 AnonymousAtom
<A
>::AnonymousAtom(Reader
<A
>& owner
, const macho_section
<P
>* section
, pint_t addr
, pint_t size
)
987 : fOwner(owner
), fSynthesizedName(NULL
), fDisplayName(NULL
), fSection(section
), fAddress(addr
), fSize(size
),
988 fSegment(NULL
), fDontDeadStrip(true), fWeakImportStub(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn
),
989 fScope(ObjectFile::Atom::scopeTranslationUnit
), fKind(ObjectFile::Atom::kRegularDefinition
),
990 fType(ObjectFile::Atom::kUnclassifiedType
), fSectionIndex(1 + (section
- owner
.fSectionsStart
))
992 fSegment
= new Segment
<A
>(fSection
);
994 uint8_t type
= fSection
->flags() & SECTION_TYPE
;
995 //fprintf(stderr, "AnonymousAtom(%p) addr=0x%llX in %s from %s\n", this, (long long)addr, section->sectname(), owner.getPath());
999 asprintf((char**)&fSynthesizedName
, "zero-fill-at-0x%08X", addr
);
1004 if ( section
== owner
.fehFrameSection
) {
1008 fDontDeadStrip
= false;
1009 if ( fOwner
.fOptions
.fForFinalLinkedImage
)
1010 fSynthesizedName
= "CIE";
1012 fSynthesizedName
= "EH_frame1";
1016 fSynthesizedName
= ".eh_PENDING";
1017 fDontDeadStrip
= false;
1018 owner
.fAtomsPendingAName
.push_back(this);
1020 fType
= ObjectFile::Atom::kCFIType
;
1021 // FDEs and CIEs don't need to be in symbol table of final linked images <rdar://problem/4180168>
1022 if ( !fOwner
.fOptions
.fNoEHLabels
)
1023 fSymbolTableInclusion
= ObjectFile::Atom::kSymbolTableIn
;
1025 else if ( (strcmp(section
->sectname(), "__class") == 0) && (strcmp(section
->segname(), "__OBJC") == 0) && owner
.fAppleObjc
) {
1026 // special case ObjC classes to synthesize .objc_class_name_* symbols, for Apple runtime only
1027 fSynthesizedName
= ".objc_class_name_PENDING";
1028 owner
.fAtomsPendingAName
.push_back(this);
1029 owner
.fSectionsWithAtomsPendingAName
.insert(fSection
);
1030 if ( fOwner
.fOptions
.fForFinalLinkedImage
)
1031 fSymbolTableInclusion
= ObjectFile::Atom::kSymbolTableIn
;
1033 fSymbolTableInclusion
= ObjectFile::Atom::kSymbolTableInAsAbsolute
;
1034 fScope
= ObjectFile::Atom::scopeGlobal
;
1036 else if ( strcmp(fSection
->sectname(), "__cstring") == 0 ) {
1037 // handle .o files created by old ld64 -r that are missing cstring section type
1038 const char* str
= (char*)(owner
.fHeader
) + section
->offset() + addr
- section
->addr();
1039 asprintf((char**)&fSynthesizedName
, "cstring=%s", str
);
1041 else if ((strcmp(section
->sectname(), "__cfstring") == 0) && (strcmp(section
->segname(), "__DATA") == 0)) {
1042 fSynthesizedName
= "cfstring-pointer-name-PENDING";
1043 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
1044 owner
.fAtomsPendingAName
.push_back(this);
1045 owner
.fSectionsWithAtomsPendingAName
.insert(fSection
);
1046 fDontDeadStrip
= false;
1047 fKind
= ObjectFile::Atom::kWeakDefinition
;
1049 else if ( (fSection
->flags() & S_ATTR_SOME_INSTRUCTIONS
) != 0 ) {
1050 fDontDeadStrip
= false;
1051 asprintf((char**)&fSynthesizedName
, "anon-func-0x%X", addr
);
1053 else if ( strncmp(fSection
->sectname(), "__gcc_except_tab",16) == 0 ) {
1054 fType
= ObjectFile::Atom::kLSDAType
;
1055 fDontDeadStrip
= false;
1056 fSynthesizedName
= ".lsda_PENDING";
1057 owner
.fAtomsPendingAName
.push_back(this);
1058 if ( !fOwner
.fOptions
.fNoEHLabels
)
1059 fSymbolTableInclusion
= ObjectFile::Atom::kSymbolTableIn
;
1061 else if ( section
== owner
.fUTF16Section
) {
1062 if ( fOwner
.fOptions
.fForFinalLinkedImage
) {
1063 fDontDeadStrip
= false;
1064 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
1065 fKind
= ObjectFile::Atom::kWeakDefinition
;
1066 char* name
= new char[16+5*size
];
1067 strcpy(name
, "utf16-string=");
1068 char* s
= &name
[13];
1069 const uint16_t* words
= (uint16_t*)((char*)(owner
.fHeader
) + section
->offset() + addr
- section
->addr());
1070 unsigned int wordCount
= size
/2;
1071 // note, the compiler sometimes puts trailing zeros on the end of the data
1072 if ( E::get32(words
[wordCount
-1]) == 0 )
1074 bool needSeperator
= false;
1075 for(unsigned int i
=0; i
< wordCount
; ++i
) {
1076 if ( needSeperator
)
1078 sprintf(s
, "%04X", E::get32(words
[i
]));
1080 needSeperator
= true;
1082 fSynthesizedName
= name
;
1085 asprintf((char**)&fSynthesizedName
, "lutf16-0x%X", addr
);
1089 case S_CSTRING_LITERALS
:
1091 const char* str
= (char*)(owner
.fHeader
) + section
->offset() + addr
- section
->addr();
1092 if ( (strcmp(fSection
->sectname(), "__cstring") == 0) && (strcmp(section
->segname(), "__TEXT") == 0) )
1093 asprintf((char**)&fSynthesizedName
, "cstring=%s", str
);
1095 asprintf((char**)&fSynthesizedName
, "cstring%s%s=%s", fSection
->segname(), fSection
->sectname(), str
);
1096 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
1097 fKind
= ObjectFile::Atom::kWeakDefinition
;
1098 fType
= ObjectFile::Atom::kCStringType
;
1099 fDontDeadStrip
= false;
1100 if ( !fOwner
.fOptions
.fForFinalLinkedImage
&& cstringsHaveLabels() )
1101 fSymbolTableInclusion
= ObjectFile::Atom::kSymbolTableIn
;
1104 case S_4BYTE_LITERALS
:
1106 uint32_t value
= E::get32(*(uint32_t*)(((uint8_t*)owner
.fHeader
) + section
->offset() + addr
- section
->addr()));
1107 asprintf((char**)&fSynthesizedName
, "4-byte-literal=0x%08X", value
);
1108 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
1109 fKind
= ObjectFile::Atom::kWeakDefinition
;
1110 fDontDeadStrip
= false;
1113 case S_8BYTE_LITERALS
:
1115 uint64_t value
= E::get64(*(uint64_t*)(((uint8_t*)owner
.fHeader
) + section
->offset() + addr
- section
->addr()));
1116 asprintf((char**)&fSynthesizedName
, "8-byte-literal=0x%016llX", value
);
1117 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
1118 fKind
= ObjectFile::Atom::kWeakDefinition
;
1119 fDontDeadStrip
= false;
1122 case S_16BYTE_LITERALS
:
1124 uint64_t value1
= E::get64(*(uint64_t*)(((uint8_t*)owner
.fHeader
) + section
->offset() + addr
- section
->addr()));
1125 uint64_t value2
= E::get64(*(uint64_t*)(((uint8_t*)owner
.fHeader
) + section
->offset() + addr
+ 8 - section
->addr()));
1126 asprintf((char**)&fSynthesizedName
, "16-byte-literal=0x%016llX,%016llX", value1
, value2
);
1127 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
1128 fKind
= ObjectFile::Atom::kWeakDefinition
;
1129 fDontDeadStrip
= false;
1132 case S_LITERAL_POINTERS
:
1134 //uint32_t literalNameAddr = P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1135 //const char* str = (char*)(owner.fHeader) + section->offset() + literalNameAddr - section->addr();
1136 //asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", section->segname(), section->sectname(), str);
1137 fSynthesizedName
= "literal-pointer-name-PENDING";
1138 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
1139 fKind
= ObjectFile::Atom::kWeakDefinition
;
1140 fDontDeadStrip
= false;
1141 owner
.fAtomsPendingAName
.push_back(this);
1142 owner
.fSectionsWithAtomsPendingAName
.insert(fSection
);
1145 case S_MOD_INIT_FUNC_POINTERS
:
1146 asprintf((char**)&fSynthesizedName
, "initializer$%d", (addr
- (uint32_t)fSection
->addr())/sizeof(pint_t
));
1148 case S_MOD_TERM_FUNC_POINTERS
:
1149 asprintf((char**)&fSynthesizedName
, "terminator$%d", (addr
- (uint32_t)fSection
->addr())/sizeof(pint_t
));
1151 case S_SYMBOL_STUBS
:
1153 uint32_t index
= (fAddress
- fSection
->addr()) / fSection
->reserved2();
1154 index
+= fSection
->reserved1();
1155 uint32_t symbolIndex
= E::get32(fOwner
.fIndirectTable
[index
]);
1156 const macho_nlist
<P
>* sym
= &fOwner
.fSymbols
[symbolIndex
];
1157 uint32_t strOffset
= sym
->n_strx();
1158 // want name to not have $stub suffix, this is what automatic stub generation expects
1159 fSynthesizedName
= &fOwner
.fStrings
[strOffset
];
1160 // check for weak import
1161 fWeakImportStub
= fOwner
.isWeakImportSymbol(sym
);
1162 // sometimes the compiler gets confused and generates a stub to a static function
1163 // if so, we should redirect any call to the stub to be calls to the real static function atom
1164 if ( ((sym
->n_type() & N_TYPE
) != N_UNDF
) && ((sym
->n_type() & N_EXT
) == 0) ) {
1165 BaseAtom
* staticAtom
= fOwner
.findAtomByName(fSynthesizedName
);
1166 if ( staticAtom
!= NULL
)
1167 fRedirect
= staticAtom
;
1169 fKind
= ObjectFile::Atom::kWeakDefinition
;
1170 // might be a spurious stub for a static function, make stub static too
1171 if ( (sym
->n_type() & N_EXT
) == 0 )
1172 fScope
= ObjectFile::Atom::scopeTranslationUnit
;
1174 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
1177 case S_LAZY_SYMBOL_POINTERS
:
1178 case S_NON_LAZY_SYMBOL_POINTERS
:
1180 // transform i386 __IMPORT/__pointers to __DATA/__nl_symbol_ptr when
1181 // generating the new compressed LINKEDIT format
1182 if ( (type
== S_NON_LAZY_SYMBOL_POINTERS
) && fOwner
.fOptions
.fMakeCompressedDyldInfo
&& (strcmp(fSection
->segname(),"__IMPORT") == 0) ) {
1183 macho_section
<P
>* dummySection
= new macho_section
<P
>(*fSection
);
1184 dummySection
->set_segname("__DATA");
1185 dummySection
->set_sectname("__nl_symbol_ptr");
1186 fSection
= dummySection
;
1187 fSegment
= new Segment
<A
>(fSection
);
1190 fDontDeadStrip
= false;
1191 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
1192 uint32_t index
= (fAddress
- fSection
->addr()) / sizeof(pint_t
);
1193 index
+= fSection
->reserved1();
1194 uint32_t symbolIndex
= E::get32(fOwner
.fIndirectTable
[index
]);
1195 if ( symbolIndex
== INDIRECT_SYMBOL_LOCAL
) {
1196 // Silly codegen with non-lazy pointer to a local symbol
1197 uint32_t fileOffset
= fSection
->offset() - fSection
->addr() + fAddress
;
1198 pint_t nonLazyPtrValue
= P::getP(*((pint_t
*)((char*)(fOwner
.fHeader
)+fileOffset
)));
1199 // All atoms not created yet, so we need to scan symbol table
1200 const macho_nlist
<P
>* closestSym
= NULL
;
1201 const macho_nlist
<P
>* end
= &fOwner
.fSymbols
[fOwner
.fSymbolCount
];
1202 for (const macho_nlist
<P
>* sym
= fOwner
.fSymbols
; sym
< end
; ++sym
) {
1203 if ( ((sym
->n_type() & N_TYPE
) == N_SECT
)
1204 && ((sym
->n_type() & N_STAB
) == 0) ) {
1205 if ( sym
->n_value() == nonLazyPtrValue
) {
1206 const char* name
= &fOwner
.fStrings
[sym
->n_strx()];
1207 char* str
= new char[strlen(name
)+16];
1209 strcat(str
, "$non_lazy_ptr");
1210 fSynthesizedName
= str
;
1211 // add direct reference to target later, because its atom may not be constructed yet
1212 fOwner
.fLocalNonLazys
.push_back(this);
1213 fScope
= ObjectFile::Atom::scopeTranslationUnit
;
1214 fType
= ObjectFile::Atom::kNonLazyPointer
;
1217 else if ( (sym
->n_value() < nonLazyPtrValue
) && ((closestSym
== NULL
) || (sym
->n_value() > closestSym
->n_value())) ) {
1222 // add direct reference to target later, because its atom may not be constructed yet
1223 if ( closestSym
!= NULL
) {
1224 const char* name
= &fOwner
.fStrings
[closestSym
->n_strx()];
1226 asprintf(&str
, "%s+%u$non_lazy_ptr", name
, nonLazyPtrValue
- closestSym
->n_value());
1227 fSynthesizedName
= str
;
1230 fSynthesizedName
= "$interior$non_lazy_ptr";
1232 fScope
= ObjectFile::Atom::scopeTranslationUnit
;
1233 fOwner
.fLocalNonLazys
.push_back(this);
1234 fType
= ObjectFile::Atom::kNonLazyPointer
;
1237 const macho_nlist
<P
>* targetSymbol
= &fOwner
.fSymbols
[symbolIndex
];
1238 const char* name
= &fOwner
.fStrings
[targetSymbol
->n_strx()];
1239 char* str
= new char[strlen(name
)+16];
1241 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
1242 strcat(str
, "$lazy_ptr");
1243 fType
= ObjectFile::Atom::kLazyPointer
;
1246 strcat(str
, "$non_lazy_ptr");
1247 fType
= ObjectFile::Atom::kNonLazyPointer
;
1249 fSynthesizedName
= str
;
1251 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
)
1252 fKind
= ObjectFile::Atom::kWeakDefinition
;
1254 if ( (targetSymbol
->n_type() & N_EXT
) == 0 ) {
1255 // target is translation unit scoped, so add direct reference to target
1256 //fOwner.makeReference(A::kPointer, addr, targetSymbol->n_value());
1257 new Reference
<A
>(A::kPointer
, AtomAndOffset(this), fOwner
.findAtomAndOffset(targetSymbol
->n_value()));
1260 if ( fOwner
.isWeakImportSymbol(targetSymbol
) )
1261 new Reference
<A
>(A::kPointerWeakImport
, AtomAndOffset(this), name
, 0);
1263 new Reference
<A
>(A::kPointer
, AtomAndOffset(this), name
, 0);
1268 throwf("section type %d not supported with address=0x%08llX", type
, (uint64_t)addr
);
1270 //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName());
1273 // x86_64 uses L labels on cstrings to allow relocs with addends
1274 template <> bool AnonymousAtom
<x86_64
>::cstringsHaveLabels() { return true; }
1275 template <typename A
> bool AnonymousAtom
<A
>::cstringsHaveLabels() { return false; }
1277 template <typename A
>
1278 void AnonymousAtom
<A
>::addLineInfo(const ObjectFile::LineInfo
& info
)
1280 // <rdar://problem/6545406> don't warn if line table has entries for stubs
1281 if ( (fSection
->flags() & SECTION_TYPE
) != S_SYMBOL_STUBS
)
1282 warning("can't add line info to anonymous symbol %s from %s", this->getDisplayName(), this->getFile()->getPath());
1285 template <typename A
>
1286 void AnonymousAtom
<A
>::resolveName()
1288 if ( (strcmp(fSection
->sectname(), "__class") == 0) && (strcmp(fSection
->segname(), "__OBJC") == 0) ) {
1289 std::vector
<ObjectFile::Reference
*>& references
= this->getReferences();
1290 // references are not yet sorted, so scan the vector
1291 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1292 if ( ((*rit
)->getFixUpOffset() == sizeof(pint_t
)) && ((*rit
)->getKind() == A::kPointer
) ) {
1293 const char* superStr
= (*rit
)->getTargetName();
1294 if ( strncmp(superStr
, "cstring", 7) == 0 ) {
1295 const char* superClassName
;
1296 asprintf((char**)&superClassName
, ".objc_class_name_%s", &superStr
[8]);
1297 new Reference
<A
>(A::kNoFixUp
, AtomAndOffset(this), superClassName
, 0);
1302 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1303 if ( ((*rit
)->getFixUpOffset() == 2*sizeof(pint_t
)) && ((*rit
)->getKind() == A::kPointer
) ) {
1304 const char* classStr
= (*rit
)->getTargetName();
1305 if ( strncmp(classStr
, "cstring", 7) == 0 ) {
1306 asprintf((char**)&fSynthesizedName
, ".objc_class_name_%s", &classStr
[8]);
1312 else if ( (fSection
->flags() & SECTION_TYPE
) == S_LITERAL_POINTERS
) {
1313 std::vector
<ObjectFile::Reference
*>& references
= this->getReferences();
1314 if ( references
.size() < 1 )
1315 throwf("S_LITERAL_POINTERS section %s,%s missing relocs", fSection
->segname(), fSection
->sectname());
1316 ObjectFile::Reference
* ref
= references
[0];
1317 const char* str
= ref
->getTargetName();
1318 if ( strncmp(str
, "cstring", 7) == 0 ) {
1319 asprintf((char**)&fSynthesizedName
, "literal-pointer@%s@%s@%s", fSection
->segname(), fSection
->sectname(), &str
[8]);
1322 else if ( (strcmp(fSection
->sectname(), "__cfstring") == 0) && (strcmp(fSection
->segname(), "__DATA") == 0) ) {
1323 // references are not yet sorted, so scan the vector
1324 std::vector
<ObjectFile::Reference
*>& references
= this->getReferences();
1325 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1326 if ( ((*rit
)->getFixUpOffset() == 2*sizeof(pint_t
)) && ((*rit
)->getKind() == A::kPointer
) ) {
1327 const char* superStr
= (*rit
)->getTargetName();
1328 if ( (superStr
!= NULL
) && (strncmp(superStr
, "cstring=", 8) == 0) ) {
1329 asprintf((char**)&fSynthesizedName
, "cfstring=%s", &superStr
[8]);
1331 else if ( (superStr
!= NULL
) && (strncmp(superStr
, "utf16-string=", 13) == 0) ) {
1332 asprintf((char**)&fSynthesizedName
, "cfstring-utf16=%s", &superStr
[13]);
1335 // compiled with -fwritable-strings or a non-ASCII string
1336 fKind
= ObjectFile::Atom::kRegularDefinition
; // these are not coalescable
1337 fScope
= ObjectFile::Atom::scopeTranslationUnit
;
1338 fSynthesizedName
= "cfstring-not-coalesable";
1339 if ( (*rit
)->getTargetOffset() != 0 )
1340 warning("-fwritable-strings not compatible with literal CF/NSString in %s", fOwner
.getPath());
1346 else if ( fSection
== fOwner
.fehFrameSection
) {
1348 ObjectFile::Atom
* funcAtom
= fOwner
.getFunctionAtomFromFDEAddress(fAddress
);
1349 if ( funcAtom
!= NULL
)
1350 asprintf((char**)&fSynthesizedName
, "%s.eh", funcAtom
->getDisplayName());
1352 else if ( fOwner
.fLSDAAtoms
.count(this) != 0) {
1353 // give name to LSDA
1354 ObjectFile::Atom
* funcAtom
= fOwner
.getFunctionAtomFromLSDAAddress(fAddress
);
1355 if ( funcAtom
!= NULL
)
1356 asprintf((char**)&fSynthesizedName
, "%s.lsda", funcAtom
->getDisplayName());
1361 template <typename A
>
1362 const char* AnonymousAtom
<A
>::getDisplayName() const
1364 if ( fSynthesizedName
!= NULL
)
1365 return fSynthesizedName
;
1367 if ( fDisplayName
!= NULL
)
1368 return fDisplayName
;
1370 if ( (fSection
->flags() & SECTION_TYPE
) == S_CSTRING_LITERALS
) {
1371 uint32_t fileOffset
= fSection
->offset() - fSection
->addr() + fAddress
;
1372 asprintf((char**)&fDisplayName
, "atom string literal: \"%s\"", (char*)(fOwner
.fHeader
)+fileOffset
);
1375 asprintf((char**)&fDisplayName
, "%s@%d", fSection
->sectname(), fAddress
- (uint32_t)fSection
->addr() );
1377 return fDisplayName
;
1381 template <typename A
>
1382 ObjectFile::Atom::Scope AnonymousAtom
<A
>::getScope() const
1388 template <typename A
>
1389 bool AnonymousAtom
<A
>::isZeroFill() const
1391 return ( ((fSection
->flags() & SECTION_TYPE
) == S_ZEROFILL
) && fOwner
.fOptions
.fOptimizeZeroFill
);
1395 template <typename A
>
1396 const char* AnonymousAtom
<A
>::getSectionName() const
1398 if ( fOwner
.fOptions
.fForFinalLinkedImage
) {
1399 switch ( fSection
->flags() & SECTION_TYPE
) {
1400 case S_4BYTE_LITERALS
:
1401 case S_8BYTE_LITERALS
:
1402 case S_16BYTE_LITERALS
:
1407 if ( strlen(fSection
->sectname()) > 15 ) {
1408 static char temp
[18];
1409 strncpy(temp
, fSection
->sectname(), 16);
1413 return fSection
->sectname();
1416 template <typename A
>
1417 ObjectFile::Alignment AnonymousAtom
<A
>::getAlignment() const
1419 // FDEs and CIEs are always packed together in a final linked image, so ignore section alignment
1420 if ( fType
== ObjectFile::Atom::kCFIType
)
1421 return ObjectFile::Alignment(0);
1423 switch ( fSection
->flags() & SECTION_TYPE
) {
1424 case S_4BYTE_LITERALS
:
1425 return ObjectFile::Alignment(2);
1426 case S_8BYTE_LITERALS
:
1427 return ObjectFile::Alignment(3);
1428 case S_16BYTE_LITERALS
:
1429 return ObjectFile::Alignment(4);
1430 case S_NON_LAZY_SYMBOL_POINTERS
:
1431 return ObjectFile::Alignment((uint8_t)log2(sizeof(pint_t
)));
1432 case S_CSTRING_LITERALS
:
1433 if ( ! fOwner
.fOptions
.fForFinalLinkedImage
)
1434 return ObjectFile::Alignment(fSection
->align());
1436 return ObjectFile::Alignment(fSection
->align(), fAddress
% (1 << fSection
->align()));
1441 template <typename A
>
1442 ObjectFile::Atom
& AnonymousAtom
<A
>::getFollowOnAtom() const
1444 for (ReferenceVectorConstIterator it
=fReferences
.begin(); it
!= fReferences
.end(); it
++) {
1445 Reference
<A
>* ref
= *it
;
1446 if ( ref
->getKind() == A::kFollowOn
)
1447 return ref
->getTarget();
1449 return *((ObjectFile::Atom
*)NULL
);
1452 template <typename A
>
1453 void AnonymousAtom
<A
>::copyRawContent(uint8_t buffer
[]) const
1457 bzero(buffer
, fSize
);
1459 uint32_t fileOffset
= fSection
->offset() - fSection
->addr() + fAddress
;
1460 memcpy(buffer
, (char*)(fOwner
.fHeader
)+fileOffset
, fSize
);
1465 // An AbsoluteAtom represents an N_ABS symbol which can only be created in
1466 // assembly language and usable by static executables such as the kernel/
1468 template <typename A
>
1469 class AbsoluteAtom
: public BaseAtom
1472 virtual ObjectFile::Reader
* getFile() const { return &fOwner
; }
1473 virtual bool getTranslationUnitSource(const char** dir
, const char** name
) const
1474 { return fOwner
.getTranslationUnitSource(dir
, name
); }
1475 virtual const char* getName() const { return &fOwner
.fStrings
[fSymbol
->n_strx()]; }
1476 virtual const char* getDisplayName() const { return getName(); }
1477 virtual ObjectFile::Atom::Scope
getScope() const { return fScope
; }
1478 virtual ObjectFile::Atom::DefinitionKind
getDefinitionKind() const { return ObjectFile::Atom::kAbsoluteSymbol
; }
1479 virtual bool isZeroFill() const { return false; }
1480 virtual bool isThumb() const { return ((fSymbol
->n_desc() & N_ARM_THUMB_DEF
) != 0); }
1481 virtual SymbolTableInclusion
getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableInAsAbsolute
; }
1482 virtual bool dontDeadStrip() const { return false; }
1483 virtual uint64_t getSize() const { return 0; }
1484 virtual std::vector
<ObjectFile::Reference
*>& getReferences() const { return fgNoReferences
; }
1485 virtual bool mustRemainInSection() const { return true; }
1486 virtual const char* getSectionName() const { return "._absolute"; }
1487 virtual ObjectFile::Segment
& getSegment() const { return LinkEditSegment::fgSingleton
; }
1488 virtual ObjectFile::Atom
& getFollowOnAtom() const { return *(ObjectFile::Atom
*)NULL
; }
1489 virtual std::vector
<ObjectFile::LineInfo
>* getLineInfo() const { return NULL
; }
1490 virtual ObjectFile::Alignment
getAlignment() const { return ObjectFile::Alignment(0); }
1491 virtual void copyRawContent(uint8_t buffer
[]) const { }
1492 virtual void setScope(ObjectFile::Atom::Scope newScope
) { fScope
= newScope
; }
1493 virtual void setSize(uint64_t size
) { }
1494 virtual void addReference(ObjectFile::Reference
* ref
) { throw "ld: can't add references"; }
1495 virtual void sortReferences() { }
1496 virtual void addLineInfo(const ObjectFile::LineInfo
& info
) { throw "ld: can't add line info to tentative definition"; }
1497 virtual const ObjectFile::ReaderOptions
& getOptions() const { return fOwner
.fOptions
; }
1498 virtual uint64_t getObjectAddress() const { return fSymbol
->n_value(); }
1499 virtual void setSectionOffset(uint64_t offset
) { /* don't let fSectionOffset be altered*/ }
1500 virtual const void* getSectionRecord() const { return NULL
; }
1501 virtual unsigned int getSectionIndex() const { return 0; }
1504 typedef typename
A::P P
;
1505 typedef typename
A::P::E E
;
1506 typedef typename
A::P::uint_t pint_t
;
1507 typedef typename
A::ReferenceKinds Kinds
;
1508 friend class Reader
<A
>;
1510 AbsoluteAtom(Reader
<A
>&, const macho_nlist
<P
>*);
1511 virtual ~AbsoluteAtom() {}
1514 const macho_nlist
<P
>* fSymbol
;
1515 ObjectFile::Atom::Scope fScope
;
1516 static std::vector
<ObjectFile::Reference
*> fgNoReferences
;
1519 template <typename A
>
1520 std::vector
<ObjectFile::Reference
*> AbsoluteAtom
<A
>::fgNoReferences
;
1522 template <typename A
>
1523 AbsoluteAtom
<A
>::AbsoluteAtom(Reader
<A
>& owner
, const macho_nlist
<P
>* symbol
)
1524 : fOwner(owner
), fSymbol(symbol
)
1526 // store absolute adress in fSectionOffset
1527 fSectionOffset
= symbol
->n_value();
1529 uint8_t type
= symbol
->n_type();
1530 if ( (type
& N_EXT
) == 0 )
1531 fScope
= ObjectFile::Atom::scopeTranslationUnit
;
1532 else if ( (type
& N_PEXT
) != 0 )
1533 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
1535 fScope
= ObjectFile::Atom::scopeGlobal
;
1536 //fprintf(stderr, "AbsoluteAtom(%p) %s\n", this, this->getDisplayName());
1541 // An SectionBoundaryAtom represent the start or end of a section
1543 template <typename A
>
1544 class SectionBoundaryAtom
: public BaseAtom
1547 virtual ObjectFile::Reader
* getFile() const { return &fOwner
; }
1548 virtual bool getTranslationUnitSource(const char** dir
, const char** name
) const
1549 { return fOwner
.getTranslationUnitSource(dir
, name
); }
1550 virtual const char* getName() const { return fSymbolName
; }
1551 virtual const char* getDisplayName() const { return fDisplayName
; }
1552 virtual ObjectFile::Atom::Scope
getScope() const { return ObjectFile::Atom::scopeLinkageUnit
; }
1553 virtual ObjectFile::Atom::DefinitionKind
getDefinitionKind() const { return ObjectFile::Atom::kWeakDefinition
; }
1554 virtual ObjectFile::Atom::ContentType
getContentType() const { return fStart
? ObjectFile::Atom::kSectionStart
: ObjectFile::Atom::kSectionEnd
; }
1555 virtual bool isZeroFill() const { return false; }
1556 virtual bool isThumb() const { return false; }
1557 virtual SymbolTableInclusion
getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn
; }
1558 virtual bool dontDeadStrip() const { return false; }
1559 virtual uint64_t getSize() const { return 0; }
1560 virtual std::vector
<ObjectFile::Reference
*>& getReferences() const { return fgNoReferences
; }
1561 virtual bool mustRemainInSection() const { return true; }
1562 virtual const char* getSectionName() const { return fSectionName
; }
1563 virtual ObjectFile::Segment
& getSegment() const { return *fSegment
; }
1564 virtual ObjectFile::Atom
& getFollowOnAtom() const { return *(ObjectFile::Atom
*)NULL
; }
1565 virtual std::vector
<ObjectFile::LineInfo
>* getLineInfo() const { return NULL
; }
1566 virtual ObjectFile::Alignment
getAlignment() const { return ObjectFile::Alignment(0); }
1567 virtual void copyRawContent(uint8_t buffer
[]) const { }
1568 virtual void setScope(ObjectFile::Atom::Scope newScope
) { }
1569 virtual void setSize(uint64_t size
) { }
1570 virtual void addReference(ObjectFile::Reference
* ref
) { throw "ld: can't add references"; }
1571 virtual void sortReferences() { }
1572 virtual void addLineInfo(const ObjectFile::LineInfo
& info
) { throw "ld: can't add line info to tentative definition"; }
1573 virtual const ObjectFile::ReaderOptions
& getOptions() const { return fOwner
.fOptions
; }
1574 virtual uint64_t getObjectAddress() const { return 0; }
1575 virtual const void* getSectionRecord() const { return NULL
; }
1576 virtual unsigned int getSectionIndex() const { return 0; }
1579 typedef typename
A::P P
;
1580 typedef typename
A::P::E E
;
1581 typedef typename
A::P::uint_t pint_t
;
1582 typedef typename
A::ReferenceKinds Kinds
;
1583 friend class Reader
<A
>;
1586 class Segment
: public ObjectFile::Segment
1589 Segment(const char* name
, bool r
, bool w
, bool x
):
1590 fName(name
), fReadable(r
), fWritable(w
), fExecutable(x
) {}
1592 virtual const char* getName() const { return fName
; }
1593 virtual bool isContentReadable() const { return fReadable
; }
1594 virtual bool isContentWritable() const { return fWritable
; }
1595 virtual bool isContentExecutable() const { return fExecutable
; }
1603 SectionBoundaryAtom(Reader
<A
>&, bool start
, const char* symbolName
, const char* segSectName
);
1604 virtual ~SectionBoundaryAtom() {}
1607 class Segment
* fSegment
;
1608 const char* fSymbolName
;
1609 const char* fSectionName
;
1610 const char* fDisplayName
;
1612 static std::vector
<ObjectFile::Reference
*> fgNoReferences
;
1615 template <typename A
>
1616 std::vector
<ObjectFile::Reference
*> SectionBoundaryAtom
<A
>::fgNoReferences
;
1619 // section$start$__DATA$__my
1620 // section$end$__DATA$__my
1621 template <typename A
>
1622 SectionBoundaryAtom
<A
>::SectionBoundaryAtom(Reader
<A
>& owner
, bool start
, const char* symbolName
, const char* segSectName
)
1623 : fOwner(owner
), fSymbolName(symbolName
), fSectionName(NULL
), fStart(start
)
1625 const char* segSectDividor
= strrchr(segSectName
, '$');
1626 if ( segSectDividor
== NULL
)
1627 throwf("malformed section reference name: %s", symbolName
);
1628 fSectionName
= segSectDividor
+ 1;
1629 int segNameLen
= segSectDividor
- segSectName
;
1630 if ( segNameLen
> 16 )
1631 throwf("malformed section reference name: %s", symbolName
);
1633 strlcpy(segName
, segSectName
, segNameLen
+1);
1634 if ( strcmp(segName
, "__TEXT") == 0 )
1635 fSegment
= new Segment("__TEXT", true, false, true);
1636 else if ( strcmp(segName
, "__DATA") == 0 )
1637 fSegment
= new Segment("__DATA", true, true, false);
1639 fSegment
= new Segment(strdup(segName
), true, true, false);
1641 asprintf((char**)&fDisplayName
, "%s of section '%s' in segment '%s'", (start
? "start" : "end"), fSectionName
, segName
);
1647 /// ObjectFileAddressSpace is used as a template parameter to UnwindCursor for parsing
1648 /// dwarf CFI information in an object file.
1650 template <typename A
>
1651 class ObjectFileAddressSpace
1654 ObjectFileAddressSpace(Reader
<A
>& reader
);
1656 typedef typename
A::P::uint_t pint_t
;
1657 typedef typename
A::P P
;
1658 typedef typename
A::P::uint_t sint_t
;
1660 uint8_t get8(pint_t addr
);
1661 uint16_t get16(pint_t addr
);
1662 uint32_t get32(pint_t addr
);
1663 uint64_t get64(pint_t addr
);
1664 pint_t
getP(pint_t addr
);
1665 uint64_t getULEB128(pint_t
& addr
, pint_t end
);
1666 int64_t getSLEB128(pint_t
& addr
, pint_t end
);
1667 pint_t
getEncodedP(pint_t
& addr
, pint_t end
, uint8_t encoding
);
1669 const void* mappedAddress(pint_t addr
, pint_t
* relocTarget
=NULL
);
1670 pint_t
relocated(uint32_t sectOffset
, uint32_t relocsOffset
, uint32_t relocsCount
);
1671 void buildRelocatedMap(const macho_section
<P
>* sect
, std::map
<uint32_t,uint64_t>& map
);
1674 const uint8_t* fMappingStart
;
1675 const macho_section
<P
>* fSectionsStart
;
1676 const macho_section
<P
>* fSectionsEnd
;
1677 std::map
<uint32_t,uint64_t> fEHFrameOffsetToTargetMap
;
1681 template <typename A
>
1682 ObjectFileAddressSpace
<A
>::ObjectFileAddressSpace(Reader
<A
>& reader
)
1683 : fReader(reader
), fMappingStart(NULL
), fSectionsStart(NULL
), fSectionsEnd(NULL
)
1689 template <typename A
>
1690 const void* ObjectFileAddressSpace
<A
>::mappedAddress(pint_t addr
, pint_t
* relocTarget
)
1692 if ( fMappingStart
== NULL
) {
1693 // delay initialization until now when fReader.fSegment is set up
1694 fMappingStart
= (uint8_t*)fReader
.fHeader
;
1695 fSectionsStart
= (macho_section
<P
>*)((char*)fReader
.fSegment
+ sizeof(macho_segment_command
<P
>));
1696 fSectionsEnd
= &fSectionsStart
[fReader
.fSegment
->nsects()];
1697 // find __eh_frame section and build map of relocations for performance
1698 buildRelocatedMap(fReader
.fehFrameSection
, fEHFrameOffsetToTargetMap
);
1700 // special case lookups in __eh_frame section to be fast
1701 const macho_section
<P
>* ehSect
= fReader
.fehFrameSection
;
1702 if ( (ehSect
->addr() <= addr
) && (addr
< (ehSect
->addr()+ehSect
->size())) ) {
1703 pint_t offsetOfAddrInSection
= addr
- ehSect
->addr();
1704 if ( relocTarget
!= NULL
) {
1705 std::map
<uint32_t,uint64_t>::iterator pos
= fEHFrameOffsetToTargetMap
.find(offsetOfAddrInSection
);
1706 if ( pos
!= fEHFrameOffsetToTargetMap
.end() )
1707 *relocTarget
= pos
->second
;
1711 return fMappingStart
+ ehSect
->offset() + offsetOfAddrInSection
;
1714 for (const macho_section
<P
>* sect
=fSectionsStart
; sect
< fSectionsEnd
; ++sect
) {
1715 if ( (sect
->addr() <= addr
) && (addr
< (sect
->addr()+sect
->size())) ) {
1716 pint_t offsetOfAddrInSection
= addr
- sect
->addr();
1717 if ( (sect
->flags() & SECTION_TYPE
) == S_NON_LAZY_SYMBOL_POINTERS
) {
1718 const uint32_t indirectTableOffset
= sect
->reserved1();
1719 const uint32_t sectionIndex
= offsetOfAddrInSection
/sizeof(pint_t
);
1720 const uint32_t symbolIndex
= A::P::E::get32(fReader
.fIndirectTable
[indirectTableOffset
+sectionIndex
]);
1721 // return pointer to symbol name which this non-lazy-pointer will point to
1722 if ( relocTarget
!= NULL
)
1723 *relocTarget
= (uintptr_t)&fReader
.fStrings
[fReader
.fSymbols
[symbolIndex
].n_strx()];
1726 if ( relocTarget
!= NULL
)
1727 *relocTarget
= relocated(offsetOfAddrInSection
, sect
->reloff(), sect
->nreloc());
1729 return fMappingStart
+ sect
->offset() + offsetOfAddrInSection
;
1732 throwf("ObjectFileAddressSpace::mappedAddress(0x%0lX) not in any section", (long)addr
);
1739 template <typename A
>
1740 uint8_t ObjectFileAddressSpace
<A
>::get8(pint_t logicalAddr
)
1742 return *((uint8_t*)mappedAddress(logicalAddr
));
1745 template <typename A
>
1746 uint16_t ObjectFileAddressSpace
<A
>::get16(pint_t logicalAddr
)
1748 return P::E::get16(*((uint16_t*)mappedAddress(logicalAddr
)));
1751 template <typename A
>
1752 uint32_t ObjectFileAddressSpace
<A
>::get32(pint_t logicalAddr
)
1755 return P::E::get32(*((uint32_t*)mappedAddress(logicalAddr
, &relocTarget
))) + relocTarget
;
1758 template <typename A
>
1759 uint64_t ObjectFileAddressSpace
<A
>::get64(pint_t logicalAddr
)
1762 return P::E::get64(*((uint64_t*)mappedAddress(logicalAddr
, &relocTarget
))) + relocTarget
;
1765 template <typename A
>
1766 typename
A::P::uint_t ObjectFileAddressSpace
<A
>::getP(pint_t logicalAddr
)
1769 return P::getP(*((pint_t
*)mappedAddress(logicalAddr
, &relocTarget
))) + relocTarget
;
1772 template <typename A
>
1773 uint64_t ObjectFileAddressSpace
<A
>::getULEB128(pint_t
& logicalAddr
, pint_t end
)
1775 uintptr_t size
= (end
- logicalAddr
);
1776 libunwind::LocalAddressSpace::pint_t laddr
= (libunwind::LocalAddressSpace::pint_t
)mappedAddress(logicalAddr
);
1777 libunwind::LocalAddressSpace::pint_t sladdr
= laddr
;
1778 uint64_t result
= libunwind::LocalAddressSpace::getULEB128(laddr
, laddr
+size
);
1779 logicalAddr
+= (laddr
-sladdr
);
1783 template <typename A
>
1784 int64_t ObjectFileAddressSpace
<A
>::getSLEB128(pint_t
& logicalAddr
, pint_t end
)
1786 uintptr_t size
= (end
- logicalAddr
);
1787 libunwind::LocalAddressSpace::pint_t laddr
= (libunwind::LocalAddressSpace::pint_t
)mappedAddress(logicalAddr
);
1788 libunwind::LocalAddressSpace::pint_t sladdr
= laddr
;
1789 int64_t result
= libunwind::LocalAddressSpace::getSLEB128(laddr
, laddr
+size
);
1790 logicalAddr
+= (laddr
-sladdr
);
1799 template <typename A
>
1800 class Reader
: public ObjectFile::Reader
1803 static bool validFile(const uint8_t* fileContent
, bool subtypeMustMatch
=false, cpu_subtype_t subtype
=0);
1804 Reader(const uint8_t* fileContent
, const char* path
, time_t modTime
,
1805 const ObjectFile::ReaderOptions
& options
, uint32_t ordinalBase
);
1806 virtual ~Reader() {}
1808 virtual const char* getPath() { return fPath
; }
1809 virtual time_t getModificationTime() { return fModTime
; }
1810 virtual ObjectFile::Reader::DebugInfoKind
getDebugInfoKind() { return fDebugInfo
; }
1811 virtual std::vector
<class ObjectFile::Atom
*>& getAtoms() { return (std::vector
<class ObjectFile::Atom
*>&)(fAtoms
); }
1812 virtual std::vector
<class ObjectFile::Atom
*>* getJustInTimeAtomsFor(const char* name
) { return NULL
; }
1813 virtual std::vector
<Stab
>* getStabs() { return &fStabs
; }
1814 virtual ObjectFile::Reader::ObjcConstraint
getObjCConstraint() { return fObjConstraint
; }
1815 virtual uint32_t updateCpuConstraint(uint32_t current
);
1816 virtual bool canScatterAtoms() { return (fHeader
->flags() & MH_SUBSECTIONS_VIA_SYMBOLS
); }
1817 virtual bool objcReplacementClasses(){ return fReplacementClasses
; }
1818 virtual bool hasLongBranchStubs() { return fHasLongBranchStubs
; }
1820 bool getTranslationUnitSource(const char** dir
, const char** name
) const;
1823 typedef typename
A::P P
;
1824 typedef typename
A::P::E E
;
1825 typedef typename
A::P::uint_t pint_t
;
1826 //typedef typename std::vector<Atom<A>*> AtomVector;
1827 //typedef typename AtomVector::iterator AtomVectorIterator; // seems to help C++ parser
1828 typedef typename
A::ReferenceKinds Kinds
;
1829 typedef typename
libunwind::CFI_Parser
<ObjectFileAddressSpace
<A
> >::FDE_Atom_Info FDE_Atom_Info
;
1830 typedef typename
libunwind::CFI_Parser
<ObjectFileAddressSpace
<A
> >::CIE_Atom_Info CIE_Atom_Info
;
1831 typedef class ObjectFileAddressSpace
<A
> OAS
;
1832 friend class ObjectFileAddressSpace
<A
>;
1833 friend class AnonymousAtom
<A
>;
1834 friend class TentativeAtom
<A
>;
1835 friend class AbsoluteAtom
<A
>;
1836 friend class SectionBoundaryAtom
<A
>;
1837 friend class SymbolAtom
<A
>;
1838 typedef std::map
<pint_t
, BaseAtom
*> AddrToAtomMap
;
1840 void addReferencesForSection(const macho_section
<P
>* sect
);
1841 bool addRelocReference(const macho_section
<P
>* sect
, const macho_relocation_info
<P
>* reloc
);
1842 bool addRelocReference_powerpc(const macho_section
<P
>* sect
, const macho_relocation_info
<P
>* reloc
);
1843 const char* getDwarfString(uint64_t form
, const uint8_t* p
);
1844 bool read_comp_unit(const char ** name
, const char ** comp_dir
, uint64_t *stmt_list
);
1845 static bool isWeakImportSymbol(const macho_nlist
<P
>* sym
);
1846 static bool skip_form(const uint8_t ** offset
, const uint8_t * end
, uint64_t form
, uint8_t addr_size
, bool dwarf64
);
1847 static const char* assureFullPath(const char* path
);
1848 AtomAndOffset
findAtomAndOffset(pint_t addr
);
1849 AtomAndOffset
findAtomAndOffsetForSection(pint_t addr
, unsigned int sectionIndex
);
1850 AtomAndOffset
findAtomAndOffset(pint_t baseAddr
, pint_t realAddr
);
1851 Reference
<A
>* makeReference(Kinds kind
, pint_t atAddr
, pint_t toAddr
);
1852 Reference
<A
>* makeReference(Kinds kind
, pint_t atAddr
, pint_t fromAddr
, pint_t toAddr
);
1853 Reference
<A
>* makeReferenceWithToBase(Kinds kind
, pint_t atAddr
, pint_t toAddr
, pint_t toBaseAddr
);
1854 Reference
<A
>* makeReferenceWithToBase(Kinds kind
, pint_t atAddr
, pint_t fromAddr
, pint_t toAddr
, pint_t toBaseAddr
);
1855 Reference
<A
>* makeByNameReference(Kinds kind
, pint_t atAddr
, const char* toName
, uint32_t toOffset
);
1856 BaseAtom
* makeReferenceToEH(const char* ehName
, pint_t ehAtomAddress
, const macho_section
<P
>* ehSect
);
1857 Reference
<A
>* makeReferenceToSymbol(Kinds kind
, pint_t atAddr
, const macho_nlist
<P
>* toSymbol
, pint_t toOffset
);
1858 void validSectionType(uint8_t type
);
1859 void addDtraceExtraInfos(uint32_t probeAddr
, const char* providerName
);
1860 void setCpuConstraint(uint32_t cpusubtype
);
1861 const macho_section
<P
>* getSectionForAddress(pint_t
);
1862 ObjectFile::Atom
* getFunctionAtomFromFDEAddress(pint_t
);
1863 ObjectFile::Atom
* getFunctionAtomFromLSDAAddress(pint_t
);
1864 void addFdeReference(uint8_t encoding
, AtomAndOffset inFDE
, AtomAndOffset target
);
1865 void addCiePersonalityReference(BaseAtom
* cieAtom
, uint32_t offsetInCIE
, uint8_t encoding
);
1866 bool isSectDiffReloc(uint8_t r_type
);
1869 BaseAtom
* findAtomByName(const char*);
1873 uint32_t fOrdinalBase
;
1874 const ObjectFile::ReaderOptions
& fOptions
;
1875 const macho_header
<P
>* fHeader
;
1876 const char* fStrings
;
1877 const macho_nlist
<P
>* fSymbols
;
1878 uint32_t fSymbolCount
;
1879 const macho_segment_command
<P
>* fSegment
;
1880 const uint32_t* fIndirectTable
;
1881 std::vector
<BaseAtom
*> fAtoms
;
1882 AddrToAtomMap fAddrToAtom
;
1883 AddrToAtomMap fAddrToAbsoluteAtom
;
1884 std::vector
<class AnonymousAtom
<A
>*> fLocalNonLazys
;
1885 std::vector
<class AnonymousAtom
<A
>*> fAtomsPendingAName
;
1886 std::set
<const macho_section
<P
>*> fSectionsWithAtomsPendingAName
;
1887 std::vector
<const char*> fDtraceProviderInfo
;
1888 ObjectFile::Reader::DebugInfoKind fDebugInfo
;
1890 const macho_section
<P
>* fehFrameSection
;
1891 const macho_section
<P
>* fUTF16Section
;
1892 std::set
<BaseAtom
*> fLSDAAtoms
;
1893 const macho_section
<P
>* fDwarfDebugInfoSect
;
1894 const macho_section
<P
>* fDwarfDebugAbbrevSect
;
1895 const macho_section
<P
>* fDwarfDebugLineSect
;
1896 const macho_section
<P
>* fDwarfDebugStringSect
;
1897 const char* fDwarfTranslationUnitDir
;
1898 const char* fDwarfTranslationUnitFile
;
1899 std::map
<uint32_t,const char*> fDwarfIndexToFile
;
1900 std::vector
<Stab
> fStabs
;
1901 std::vector
<FDE_Atom_Info
> fFDEInfos
;
1902 std::vector
<CIE_Atom_Info
> fCIEInfos
;
1904 bool fHasDTraceProbes
;
1905 bool fHaveIndirectSymbols
;
1906 bool fReplacementClasses
;
1907 bool fHasLongBranchStubs
;
1908 ObjectFile::Reader::ObjcConstraint fObjConstraint
;
1909 uint32_t fCpuConstraint
;
1910 const macho_section
<P
>* fSectionsStart
;
1911 const macho_section
<P
>* fSectionsEnd
;
1912 OAS fObjectAddressSpace
;
1915 template <typename A
>
1916 Reader
<A
>::Reader(const uint8_t* fileContent
, const char* path
, time_t modTime
, const ObjectFile::ReaderOptions
& options
, uint32_t ordinalBase
)
1917 : fPath(strdup(path
)), fModTime(modTime
), fOrdinalBase(ordinalBase
), fOptions(options
), fHeader((const macho_header
<P
>*)fileContent
),
1918 fStrings(NULL
), fSymbols(NULL
), fSymbolCount(0), fSegment(NULL
), fIndirectTable(NULL
),
1919 fDebugInfo(kDebugInfoNone
), fHasUUID(false), fehFrameSection(NULL
), fUTF16Section(NULL
),
1920 fDwarfDebugInfoSect(NULL
), fDwarfDebugAbbrevSect(NULL
), fDwarfDebugLineSect(NULL
),
1921 fDwarfTranslationUnitDir(NULL
), fDwarfTranslationUnitFile(NULL
), fAppleObjc(false), fHasDTraceProbes(false),
1922 fHaveIndirectSymbols(false), fReplacementClasses(false), fHasLongBranchStubs(false),
1923 fObjConstraint(ObjectFile::Reader::kObjcNone
), fCpuConstraint(ObjectFile::Reader::kCpuAny
),
1924 fSectionsStart(NULL
), fSectionsEnd(NULL
), fObjectAddressSpace(*this)
1927 if ( ! validFile(fileContent
, false, 0) )
1928 throw "not a valid mach-o object file";
1930 Reference
<A
>::fgForFinalLinkedImage
= options
.fForFinalLinkedImage
;
1932 // write out path for -t or -whatsloaded option
1933 if ( options
.fLogObjectFiles
|| options
.fLogAllFiles
)
1934 printf("%s\n", path
);
1936 // cache intersting pointers
1937 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
1938 this->setCpuConstraint(header
->cpusubtype());
1939 const uint32_t cmd_count
= header
->ncmds();
1940 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((char*)header
+ sizeof(macho_header
<P
>));
1941 const macho_load_command
<P
>* const cmdsEnd
= (macho_load_command
<P
>*)((char*)header
+ sizeof(macho_header
<P
>) + header
->sizeofcmds());
1942 const macho_load_command
<P
>* cmd
= cmds
;
1943 uint32_t undefinedStartIndex
= 0;
1944 uint32_t undefinedEndIndex
= 0;
1945 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1946 switch (cmd
->cmd()) {
1949 const macho_symtab_command
<P
>* symtab
= (macho_symtab_command
<P
>*)cmd
;
1950 fSymbolCount
= symtab
->nsyms();
1951 fSymbols
= (const macho_nlist
<P
>*)((char*)header
+ symtab
->symoff());
1952 fStrings
= (char*)header
+ symtab
->stroff();
1953 if ( undefinedEndIndex
== 0 ) {
1954 undefinedStartIndex
= 0;
1955 undefinedEndIndex
= symtab
->nsyms();
1961 const macho_dysymtab_command
<P
>* dsymtab
= (struct macho_dysymtab_command
<P
>*)cmd
;
1962 fIndirectTable
= (uint32_t*)((char*)fHeader
+ dsymtab
->indirectsymoff());
1963 undefinedStartIndex
= dsymtab
->iundefsym();
1964 undefinedEndIndex
= undefinedStartIndex
+ dsymtab
->nundefsym();
1972 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
1973 fSegment
= (macho_segment_command
<P
>*)cmd
;
1977 cmd
= (const macho_load_command
<P
>*)(((char*)cmd
)+cmd
->cmdsize());
1978 if ( cmd
> cmdsEnd
)
1979 throwf("malformed dylb, load command #%d is outside size of load commands in %s", i
, path
);
1982 // if there are no load commands, then this file has no content, so no atoms
1983 if ( header
->ncmds() < 1 )
1986 fSectionsStart
= (macho_section
<P
>*)((char*)fSegment
+ sizeof(macho_segment_command
<P
>));
1987 fSectionsEnd
= &fSectionsStart
[fSegment
->nsects()];
1989 // inital guess for number of atoms
1990 fAtoms
.reserve(fSymbolCount
);
1992 // if there is an __eh_frame section, decode it into chunks to get atoms in that
1993 // section as well as division points for functions in __text
1994 for (const macho_section
<P
>* sect
=fSectionsStart
; sect
< fSectionsEnd
; ++sect
) {
1995 if ( (strcmp(sect
->sectname(), "__eh_frame") == 0) && (strcmp(sect
->segname(), "__TEXT") == 0) ) {
1996 fehFrameSection
= sect
;
1997 const char* msg
= libunwind::CFI_Parser
<ObjectFileAddressSpace
<A
> >::getCFIs(fObjectAddressSpace
, sect
->addr(),
1998 sect
->size(), fFDEInfos
, fCIEInfos
);
1999 if ( msg
!= NULL
) {
2000 throwf("malformed __eh_frame section: %s", msg
);
2003 //fprintf(stderr, "%lu CIEs, %lu FDEs\n", fCIEInfos.size(), fFDEInfos.size());
2004 // add anonymous atoms for each CIE
2005 for (typename
std::vector
<CIE_Atom_Info
>::const_iterator it
= fCIEInfos
.begin(); it
!= fCIEInfos
.end(); ++it
) {
2006 AnonymousAtom
<A
>* cieAtom
= new AnonymousAtom
<A
>(*this, sect
, it
->cieAddress
, 1);
2007 fAtoms
.push_back(cieAtom
);
2008 fAddrToAtom
[it
->cieAddress
] = cieAtom
;
2010 // add anonymous atoms for each FDE and LSDA
2011 for (typename
std::vector
<FDE_Atom_Info
>::const_iterator it
= fFDEInfos
.begin(); it
!= fFDEInfos
.end(); ++it
) {
2012 //fprintf(stderr, "fdeAddress=0x%08llX, lsdaAddr=0x%08llX, funcAddr=0x%08llX\n", (uint64_t)it->fdeAddress, (uint64_t)it->lsda.address, (uint64_t)it->function.address);
2013 AnonymousAtom
<A
>* fdeAtom
= new AnonymousAtom
<A
>(*this, sect
, it
->fdeAddress
, 0);
2014 fAtoms
.push_back(fdeAtom
);
2015 fAddrToAtom
[it
->fdeAddress
] = fdeAtom
;
2016 if ( it
->lsda
.address
!= 0 ) {
2017 AnonymousAtom
<A
>* lsdaAtom
= new AnonymousAtom
<A
>(*this, getSectionForAddress(it
->lsda
.address
), it
->lsda
.address
, 0);
2018 fAtoms
.push_back(lsdaAtom
);
2019 fAddrToAtom
[it
->lsda
.address
] = lsdaAtom
;
2020 fLSDAAtoms
.insert(lsdaAtom
);
2025 else if ( (strcmp(sect
->sectname(), "__ustring") == 0) && (strcmp(sect
->segname(), "__TEXT") == 0) ) {
2026 // if there is a __ustring section parse it into AnonymousAtoms based on labels
2027 fUTF16Section
= sect
;
2028 std::vector
<pint_t
> utf16Addreses
;
2029 for (int i
=fSymbolCount
-1; i
>= 0 ; --i
) {
2030 const macho_nlist
<P
>& sym
= fSymbols
[i
];
2031 if ( (sym
.n_type() & N_STAB
) == 0 ) {
2032 uint8_t type
= (sym
.n_type() & N_TYPE
);
2033 if ( type
== N_SECT
) {
2034 if ( &fSectionsStart
[sym
.n_sect()-1] == fUTF16Section
) {
2035 utf16Addreses
.push_back(sym
.n_value());
2040 utf16Addreses
.push_back(fUTF16Section
->addr()+fUTF16Section
->size());
2041 std::sort(utf16Addreses
.begin(), utf16Addreses
.end());
2042 for(int i
=utf16Addreses
.size()-2; i
>=0 ; --i
) {
2043 pint_t size
= utf16Addreses
[i
+1] - utf16Addreses
[i
];
2044 AnonymousAtom
<A
>* strAtom
= new AnonymousAtom
<A
>(*this, fUTF16Section
, utf16Addreses
[i
], size
);
2045 fAtoms
.push_back(strAtom
);
2046 fAddrToAtom
[utf16Addreses
[i
]] = strAtom
;
2052 // add all atoms that have entries in symbol table
2053 BaseAtom
* sectionEndAtoms
[fSegment
->nsects()];
2054 for (unsigned int i
=0; i
< fSegment
->nsects(); ++i
)
2055 sectionEndAtoms
[i
] = NULL
;
2056 for (int i
=fSymbolCount
-1; i
>= 0 ; --i
) {
2057 // walk backwards through symbol table so globals are see before locals, otherwise a local alias would beome the real name
2058 const macho_nlist
<P
>& sym
= fSymbols
[i
];
2059 if ( (sym
.n_type() & N_STAB
) == 0 ) {
2060 uint8_t type
= (sym
.n_type() & N_TYPE
);
2061 if ( type
== N_SECT
) {
2062 const macho_section
<P
>* section
= &fSectionsStart
[sym
.n_sect()-1];
2063 const pint_t sectionStartAddr
= section
->addr();
2064 const pint_t sectionEndAddr
= sectionStartAddr
+ section
->size();
2065 bool suppress
= false;
2066 // ignore atoms in debugger sections
2067 if ( (section
->flags() & S_ATTR_DEBUG
) == 0 ) {
2068 if ( strncmp(&fStrings
[sym
.n_strx()], "__dtrace_probe$", 15) == 0 ) {
2069 // ignore dtrace probe labels
2070 fHasDTraceProbes
= true;
2072 else if ( fStrings
[sym
.n_strx()] == 'L' ) {
2073 // ignore L labels, <rdar://problem/3962731>
2075 else if ( section
== fehFrameSection
) {
2076 // ignore labels in __eh_frame section
2078 else if ( section
== fUTF16Section
) {
2079 // ignore labels in __ustring section
2082 // ignore labels for atoms in other sections
2083 switch ( section
->flags() & SECTION_TYPE
) {
2085 if ( (sym
.n_desc() & N_WEAK_DEF
) && strcmp(section
->sectname(), "__picsymbolstub1__TEXT") == 0 )
2086 suppress
= true; // ignore stubs in crt1.o built by old ld64 that was missing S_SYMBOL_STUBS
2089 case S_4BYTE_LITERALS
:
2090 case S_8BYTE_LITERALS
:
2091 case S_16BYTE_LITERALS
:
2092 case S_CSTRING_LITERALS
:
2095 typename
AddrToAtomMap::iterator pos
= fAddrToAtom
.find(sym
.n_value());
2096 if ( (pos
!= fAddrToAtom
.end()) && (pos
->second
->getSectionRecord() == section
) ) {
2097 if ( fLSDAAtoms
.count(pos
->second
) != 0 ) {
2098 // already have LSDA atom from for this address, ignore compiler's label
2103 // another label to an existing address in the same section, make this an alias
2104 newAtom
= new SymbolAliasAtom
<A
>(&fStrings
[sym
.n_strx()], &sym
, *pos
->second
);
2108 if ( sym
.n_value() == sectionEndAddr
) {
2109 // Symbol address is at end of section. This can interfere
2110 // with a symbol at the start of the next section, so don't
2111 // add to fAddrToAtom. But do track in sectionEndAtoms so we
2112 // still make aliases if there are duplicates.
2113 if ( sectionEndAtoms
[sym
.n_sect()-1] == NULL
) {
2114 newAtom
= new SymbolAtom
<A
>(*this, &sym
, section
);
2115 sectionEndAtoms
[sym
.n_sect()-1] = newAtom
;
2116 // if this is a zero length section, so add to fAddrToAtom
2117 if ( sym
.n_value() == sectionStartAddr
)
2118 fAddrToAtom
[newAtom
->getObjectAddress()] = newAtom
;
2121 newAtom
= new SymbolAliasAtom
<A
>(&fStrings
[sym
.n_strx()], &sym
, *sectionEndAtoms
[sym
.n_sect()-1]);
2125 // make SymbolAtom atom for this address
2126 newAtom
= new SymbolAtom
<A
>(*this, &sym
, section
);
2127 fAddrToAtom
[newAtom
->getObjectAddress()] = newAtom
;
2131 fAtoms
.push_back(newAtom
);
2134 case S_SYMBOL_STUBS
:
2135 case S_LAZY_SYMBOL_POINTERS
:
2136 case S_NON_LAZY_SYMBOL_POINTERS
:
2137 // ignore symboled stubs produces by old ld64
2140 warning("symbol %s found in unsupported section in %s",
2141 &fStrings
[sym
.n_strx()], this->getPath());
2146 else if ( (type
== N_UNDF
) && (sym
.n_value() != 0) ) {
2147 fAtoms
.push_back(new TentativeAtom
<A
>(*this, &sym
));
2149 else if ( (type
== N_UNDF
) && (sym
.n_value() == 0) ) {
2150 const char* symName
= &fStrings
[sym
.n_strx()];
2151 if ( strncmp(symName
, "section$start$", 14) == 0)
2152 fAtoms
.push_back(new SectionBoundaryAtom
<A
>(*this, true, symName
, &symName
[14]));
2153 else if ( strncmp(symName
, "section$end$", 12) == 0)
2154 fAtoms
.push_back(new SectionBoundaryAtom
<A
>(*this, false, symName
, &symName
[12]));
2156 else if ( type
== N_ABS
) {
2157 const char* symName
= &fStrings
[sym
.n_strx()];
2158 if ( strncmp(symName
, ".objc_class_name_", 17) == 0 ) {
2159 // ignore .objc_class_name_* symbols
2162 else if ( strcmp(&symName
[strlen(symName
)-3], ".eh") == 0 ) {
2163 // ignore empty *.eh symbols
2166 BaseAtom
* abAtom
= new AbsoluteAtom
<A
>(*this, &sym
);
2167 fAtoms
.push_back(abAtom
);
2168 fAddrToAbsoluteAtom
[sym
.n_value()] = abAtom
;
2171 else if ( type
== N_INDR
) {
2172 fHaveIndirectSymbols
= true;
2177 // add anonymous atoms for any functions (as determined by dwarf unwind) have no symbol names
2178 if ( fehFrameSection
!= NULL
) {
2179 for (typename
std::vector
<FDE_Atom_Info
>::const_iterator it
= fFDEInfos
.begin(); it
!= fFDEInfos
.end(); ++it
) {
2180 // add if not already an atom at that address
2181 if ( fAddrToAtom
.find(it
->function
.address
) == fAddrToAtom
.end() ) {
2182 AnonymousAtom
<A
>* funcAtom
= new AnonymousAtom
<A
>(*this, getSectionForAddress(it
->function
.address
), it
->function
.address
, 0);
2183 fAtoms
.push_back(funcAtom
);
2184 fAddrToAtom
[it
->function
.address
] = funcAtom
;
2185 // even though we've made a new atom, be conservative and make sure they lay out together
2186 if ( canScatterAtoms() ) {
2187 AtomAndOffset prev
= findAtomAndOffset(it
->function
.address
-1);
2188 if ( prev
.atom
!= NULL
) {
2189 if ( ((BaseAtom
*)(prev
.atom
))->getSectionRecord() == funcAtom
->getSectionRecord() )
2190 new Reference
<A
>(A::kFollowOn
, prev
, AtomAndOffset(funcAtom
));
2198 // add all fixed size anonymous atoms from special sections
2199 for (const macho_section
<P
>* sect
=fSectionsStart
; sect
< fSectionsEnd
; ++sect
) {
2200 pint_t atomSize
= 0;
2201 uint8_t type (sect
->flags() & SECTION_TYPE
);
2202 validSectionType(type
);
2203 bool suppress
= false;
2205 case S_SYMBOL_STUBS
:
2207 atomSize
= sect
->reserved2();
2209 case S_LAZY_SYMBOL_POINTERS
:
2211 atomSize
= sizeof(pint_t
);
2213 case S_NON_LAZY_SYMBOL_POINTERS
:
2214 case S_LITERAL_POINTERS
:
2215 case S_MOD_INIT_FUNC_POINTERS
:
2216 case S_MOD_TERM_FUNC_POINTERS
:
2217 atomSize
= sizeof(pint_t
);
2220 atomSize
= sizeof(pint_t
)*2;
2222 case S_4BYTE_LITERALS
:
2225 case S_8BYTE_LITERALS
:
2228 case S_16BYTE_LITERALS
:
2232 // special case ObjC classes to synthesize .objc_class_name_* symbols
2233 if ( (strcmp(sect
->sectname(), "__class") == 0) && (strcmp(sect
->segname(), "__OBJC") == 0) && fAppleObjc
) {
2234 // gcc sometimes over aligns class structure
2235 uint32_t align
= 1 << sect
->align();
2236 atomSize
= ((12 * sizeof(pint_t
)) + align
-1) & (-align
);
2238 // get objc Garbage Collection info
2239 else if ( ((strcmp(sect
->sectname(), "__image_info") == 0) && (strcmp(sect
->segname(), "__OBJC") == 0))
2240 || ((strncmp(sect
->sectname(), "__objc_imageinfo", 16) == 0) && (strcmp(sect
->segname(), "__DATA") == 0)) ) {
2241 // struct objc_image_info {
2242 // uint32_t version; // initially 0
2245 // #define OBJC_IMAGE_SUPPORTS_GC 2
2246 // #define OBJC_IMAGE_GC_ONLY 4
2248 const uint32_t* contents
= (uint32_t*)(((char*)fHeader
) + sect
->offset());
2249 if ( (sect
->size() >= 8) && (contents
[0] == 0) ) {
2250 uint32_t flags
= E::get32(contents
[1]);
2251 if ( (flags
& 4) == 4 )
2252 fObjConstraint
= ObjectFile::Reader::kObjcGC
;
2253 else if ( (flags
& 2) == 2 )
2254 fObjConstraint
= ObjectFile::Reader::kObjcRetainReleaseOrGC
;
2256 fObjConstraint
= ObjectFile::Reader::kObjcRetainRelease
;
2257 if ( (flags
& 1) == 1 )
2258 fReplacementClasses
= true;
2259 // don't make atom for this section
2260 atomSize
= sect
->size();
2264 warning("can't parse __OBJC/__image_info section in %s", fPath
);
2267 // special case constant NS/CFString literals and make an atom out of each one
2268 else if ((strcmp(sect
->sectname(), "__cfstring") == 0) && (strcmp(sect
->segname(), "__DATA") == 0)) {
2269 atomSize
= 4 * sizeof(pint_t
);
2273 if ( atomSize
!= 0 ) {
2274 for(pint_t sectOffset
=0; sectOffset
< sect
->size(); sectOffset
+= atomSize
) {
2275 pint_t atomAddr
= sect
->addr() + sectOffset
;
2276 // add if not already an atom at that address
2277 if ( fAddrToAtom
.find(atomAddr
) == fAddrToAtom
.end() ) {
2278 AnonymousAtom
<A
>* newAtom
= new AnonymousAtom
<A
>(*this, sect
, atomAddr
, atomSize
);
2280 fAtoms
.push_back(newAtom
);
2281 fAddrToAtom
[atomAddr
] = newAtom
->redirectTo();
2287 // add all c-string anonymous atoms
2288 for (const macho_section
<P
>* sect
=fSectionsStart
; sect
< fSectionsEnd
; ++sect
) {
2289 if ( ((sect
->flags() & SECTION_TYPE
) == S_CSTRING_LITERALS
) || strcmp(sect
->sectname(), "__cstring") == 0 ) {
2292 BaseAtom
* mostAlignedEmptyString
= NULL
;
2293 uint32_t mostAlignedEmptyStringTrailingZeros
= 0;
2294 std::vector
<std::pair
<pint_t
,BaseAtom
*> > emptyStrings
;
2295 for(pint_t sectOffset
=0; sectOffset
< sect
->size(); sectOffset
+= stringLen
) {
2296 stringAddr
= sect
->addr() + sectOffset
;
2297 stringLen
= strlen((char*)(fHeader
) + sect
->offset() + sectOffset
) + 1;
2298 // add if not already a non-zero length atom at that address
2299 typename
AddrToAtomMap::iterator pos
= fAddrToAtom
.find(stringAddr
);
2300 if ( (pos
== fAddrToAtom
.end()) || (pos
->second
->getSize() == 0) ) {
2301 BaseAtom
* newAtom
= new AnonymousAtom
<A
>(*this, sect
, stringAddr
, stringLen
);
2302 if ( stringLen
== 1 ) {
2303 // because of padding it may look like there are lots of empty strings, keep track of all
2304 emptyStrings
.push_back(std::make_pair
<pint_t
,BaseAtom
*>(stringAddr
, newAtom
));
2305 // record empty string with greatest alignment requirement
2306 uint32_t stringAddrTrailingZeros
= (stringAddr
==0) ? sect
->align() : __builtin_ctz(stringAddr
);
2307 if ( (mostAlignedEmptyString
== NULL
)
2308 || ( stringAddrTrailingZeros
> mostAlignedEmptyStringTrailingZeros
) ) {
2309 mostAlignedEmptyString
= newAtom
;
2310 mostAlignedEmptyStringTrailingZeros
= stringAddrTrailingZeros
;
2314 fAtoms
.push_back(newAtom
);
2315 fAddrToAtom
[stringAddr
] = newAtom
;
2319 // map all uses of empty strings to the most aligned one
2320 if ( mostAlignedEmptyString
!= NULL
) {
2321 // make most aligned atom a real atom
2322 fAtoms
.push_back(mostAlignedEmptyString
);
2323 // map all other empty atoms to this one
2324 for (typename
std::vector
<std::pair
<pint_t
,BaseAtom
*> >::iterator it
=emptyStrings
.begin(); it
!= emptyStrings
.end(); it
++) {
2325 fAddrToAtom
[it
->first
] = mostAlignedEmptyString
;
2331 // sort all atoms so far by address and section
2332 std::sort(fAtoms
.begin(), fAtoms
.end(), BaseAtomSorter());
2334 //fprintf(stderr, "sorted atoms:\n");
2335 //for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++)
2336 // fprintf(stderr, "0x%08llX %s\n", (*it)->getObjectAddress(), (*it)->getDisplayName());
2338 // create atoms to cover any non-debug ranges not handled above
2339 for (const macho_section
<P
>* sect
=fSectionsStart
; sect
< fSectionsEnd
; ++sect
) {
2340 pint_t sectionStartAddr
= sect
->addr();
2341 pint_t sectionEndAddr
= sect
->addr() + sect
->size();
2342 // don't set follow-on atoms in __eh_frame section
2343 const bool setFollowOnAtom
= !canScatterAtoms() && (sect
!= fehFrameSection
);
2344 if ( sect
->size() != 0 ) {
2345 // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change
2346 if ( (sect
->flags() & S_ATTR_DEBUG
) != 0 ) {
2347 fDebugInfo
= kDebugInfoDwarf
;
2348 if ( strcmp(sect
->sectname(), "__debug_info") == 0 )
2349 fDwarfDebugInfoSect
= sect
;
2350 else if ( strcmp(sect
->sectname(), "__debug_abbrev") == 0 )
2351 fDwarfDebugAbbrevSect
= sect
;
2352 else if ( strcmp(sect
->sectname(), "__debug_line") == 0 )
2353 fDwarfDebugLineSect
= sect
;
2354 else if ( strcmp(sect
->sectname(), "__debug_str") == 0 )
2355 fDwarfDebugStringSect
= sect
;
2358 if ( strcmp(sect
->segname(), "__DWARFA") == 0 ) {
2359 throw "object file contains old DWARF debug info - rebuild with newer compiler";
2361 uint8_t type (sect
->flags() & SECTION_TYPE
);
2366 // if there is not an atom already at the start of this section, add an anonymous one
2367 pint_t previousAtomAddr
= 0;
2368 BaseAtom
* previousAtom
= NULL
;
2369 if ( fAddrToAtom
.find(sectionStartAddr
) == fAddrToAtom
.end() ) {
2370 BaseAtom
* newAtom
= new AnonymousAtom
<A
>(*this, sect
, sect
->addr(), 0);
2371 fAddrToAtom
[sect
->addr()] = newAtom
;
2372 fAtoms
.push_back(newAtom
);
2373 previousAtomAddr
= sectionStartAddr
;
2374 previousAtom
= newAtom
;
2375 std::sort(fAtoms
.begin(), fAtoms
.end(), BaseAtomSorter());
2377 // calculate size of all atoms in this section and add follow-on references
2378 for (std::vector
<BaseAtom
*>::iterator it
=fAtoms
.begin(); it
!= fAtoms
.end(); it
++) {
2379 BaseAtom
* atom
= (BaseAtom
*)(*it
);
2380 pint_t atomAddr
= atom
->getObjectAddress();
2381 if ( atom
->getSectionRecord() == sect
) {
2382 //fprintf(stderr, "addr=0x%08llX, atom=%s\n", (uint64_t)atomAddr, atom->getDisplayName());
2383 if ( (previousAtom
!= NULL
) && (previousAtomAddr
!= atomAddr
) ) {
2384 previousAtom
->setSize(atomAddr
- previousAtomAddr
);
2385 if ( setFollowOnAtom
&& (atom
!= previousAtom
) )
2386 new Reference
<A
>(A::kFollowOn
, AtomAndOffset(previousAtom
), AtomAndOffset(atom
));
2388 previousAtomAddr
= atomAddr
;
2389 previousAtom
= atom
;
2392 if ( previousAtom
!= NULL
) {
2393 // set last atom in section
2394 previousAtom
->setSize(sectionEndAddr
- previousAtomAddr
);
2402 // check for object file that defines no objc classes, but uses objc classes
2403 // check for dtrace provider info
2404 for (uint32_t i
=undefinedStartIndex
; i
< undefinedEndIndex
; ++i
) {
2405 const macho_nlist
<P
>& sym
= fSymbols
[i
];
2406 if ( (sym
.n_type() & N_STAB
) == 0 ) {
2407 if ( (sym
.n_type() & N_TYPE
) == N_UNDF
) {
2408 const char* undefinedName
= &fStrings
[sym
.n_strx()];
2409 if ( !fAppleObjc
&& (strncmp(undefinedName
, ".objc_class_name_", 17) == 0) ) {
2412 else if ( strncmp(undefinedName
, "___dtrace_", 10) == 0 ) {
2413 if ( strchr(undefinedName
, '$') != NULL
) {
2414 if ( (strncmp(&undefinedName
[10], "probe$", 6) != 0) && (strncmp(&undefinedName
[10], "isenabled$", 10) != 0) ) {
2415 // any undefined starting with __dtrace_*$ that is not ___dtrace_probe$* or ___dtrace_isenabled$*
2416 // is extra provider info
2417 fDtraceProviderInfo
.push_back(undefinedName
);
2425 // add relocation based references to sections that have atoms with pending names
2426 for (const macho_section
<P
>* sect
=fSectionsStart
; sect
< fSectionsEnd
; ++sect
) {
2427 if ( fSectionsWithAtomsPendingAName
.count(sect
) != 0 )
2428 addReferencesForSection(sect
);
2431 // update any anonymous atoms that need references built in order to name themselves
2432 for (typename
std::vector
<AnonymousAtom
<A
>*>::iterator it
=fAtomsPendingAName
.begin(); it
!= fAtomsPendingAName
.end(); it
++) {
2433 (*it
)->resolveName();
2436 // add relocation based references to other sections
2437 for (const macho_section
<P
>* sect
=fSectionsStart
; sect
< fSectionsEnd
; ++sect
) {
2438 if ( fSectionsWithAtomsPendingAName
.count(sect
) == 0 )
2439 addReferencesForSection(sect
);
2442 // add objective-c references
2444 for (const macho_section
<P
>* sect
=fSectionsStart
; sect
< fSectionsEnd
; ++sect
) {
2445 if ( (strcmp(sect
->sectname(), "__cls_refs") == 0) && (strcmp(sect
->segname(), "__OBJC") == 0) ) {
2446 for (uint32_t offset
= 0; offset
< sect
->size(); offset
+= sizeof(pint_t
)) {
2447 AtomAndOffset ao
= this->findAtomAndOffset(sect
->addr()+offset
);
2448 ObjectFile::Reference
* classRef
= ao
.atom
->getReferences()[0];
2449 if ( classRef
->getFixUpOffset() == 0 ) {
2450 const char* classStr
= classRef
->getTargetName();
2451 if ( strncmp(classStr
, "cstring=", 8) == 0 ) {
2452 const char* className
;
2453 asprintf((char**)&className
, ".objc_class_name_%s", &classStr
[8]);
2454 new Reference
<A
>(A::kNoFixUp
, ao
, className
, 0);
2462 // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed
2463 for (typename
std::vector
<AnonymousAtom
<A
>*>::iterator it
=fLocalNonLazys
.begin(); it
!= fLocalNonLazys
.end(); it
++) {
2464 AnonymousAtom
<A
>* localNonLazy
= *it
;
2465 uint32_t fileOffset
= localNonLazy
->fSection
->offset() - localNonLazy
->fSection
->addr() + localNonLazy
->fAddress
;
2466 pint_t nonLazyPtrValue
= P::getP(*((pint_t
*)((char*)(fHeader
)+fileOffset
)));
2467 makeReference(A::kPointer
, localNonLazy
->fAddress
, nonLazyPtrValue
);
2471 // add personality references to CIEs
2472 for (typename
std::vector
<CIE_Atom_Info
>::const_iterator it
= fCIEInfos
.begin(); it
!= fCIEInfos
.end(); ++it
) {
2473 if ( it
->personality
.offsetInFDE
!= 0 )
2474 addCiePersonalityReference(fAddrToAtom
[it
->cieAddress
], it
->personality
.offsetInFDE
, it
->personality
.encodingOfAddress
);
2477 // add all references for FDEs, including implicit group references
2478 for (typename
std::vector
<FDE_Atom_Info
>::const_iterator it
= fFDEInfos
.begin(); it
!= fFDEInfos
.end(); ++it
) {
2479 AtomAndOffset funcAO
= this->findAtomAndOffset(it
->function
.address
);
2480 if ( funcAO
.offset
!= 0 )
2481 warning("FDE does not point to start of function %s\n", funcAO
.atom
->getDisplayName());
2482 AtomAndOffset fdeAO
= this->findAtomAndOffset(it
->fdeAddress
);
2483 if ( fdeAO
.offset
!= 0 )
2484 warning("FDE does start its own atom %s\n", funcAO
.atom
->getDisplayName());
2485 AtomAndOffset cieAO
= this->findAtomAndOffset(it
->cie
.address
);
2486 if ( cieAO
.offset
!= 0 )
2487 warning("CIE does start its own atom %s\n", cieAO
.atom
->getDisplayName());
2488 AtomAndOffset lsdaAO
;
2489 if ( it
->lsda
.address
!= 0 ) {
2490 lsdaAO
= this->findAtomAndOffset(it
->lsda
.address
);
2491 if ( lsdaAO
.offset
!= 0 )
2492 warning("LSDA does start its own atom %s\n", lsdaAO
.atom
->getDisplayName());
2495 // add reference from FDE to CIE
2496 AtomAndOffset cieInfdeAO
= AtomAndOffset(fdeAO
.atom
, it
->cie
.offsetInFDE
);
2497 new Reference
<A
>(A::kPointerDiff32
, cieInfdeAO
, cieAO
, cieInfdeAO
);
2499 // add reference from FDE to function
2500 addFdeReference(it
->function
.encodingOfAddress
, AtomAndOffset(fdeAO
.atom
, it
->function
.offsetInFDE
), funcAO
);
2502 // add reference from FDE to LSDA
2503 if ( it
->lsda
.address
!= 0 ) {
2504 addFdeReference(it
->lsda
.encodingOfAddress
, AtomAndOffset(fdeAO
.atom
, it
->lsda
.offsetInFDE
), lsdaAO
);
2507 // FDE is in group lead by function atom
2508 new Reference
<A
>(A::kGroupSubordinate
, funcAO
, fdeAO
);
2510 // LSDA is in group lead by function atom
2511 if ( it
->lsda
.address
!= 0 ) {
2512 new Reference
<A
>(A::kGroupSubordinate
, funcAO
, lsdaAO
);
2513 // add back reference from LSDA to owning function
2514 new Reference
<A
>(A::kNoFixUp
, lsdaAO
, funcAO
);
2517 // compute compact encoding for this FDE
2518 if ( fOptions
.fAddCompactUnwindEncoding
) {
2519 ((BaseAtom
*)(funcAO
.atom
))->setCompactUnwindEncoding(it
->fdeAddress
);
2520 // add reference from function atom to personality function
2521 // the only reference a CIE can have is the reference to the personality function
2522 std::vector
<class ObjectFile::Reference
*>& cieRefs
= cieAO
.atom
->getReferences();
2523 if ( cieRefs
.size() == 1 ) {
2524 new Reference
<A
>((typename
A::ReferenceKinds
)((BaseAtom
*)(funcAO
.atom
))->getPersonalityReferenceKind(),
2525 funcAO
, cieRefs
[0]->getTargetName(), 0);
2530 // add command line aliases
2531 for(std::vector
<ObjectFile::ReaderOptions::AliasPair
>::const_iterator it
= fOptions
.fAliases
.begin(); it
!= fOptions
.fAliases
.end(); ++it
) {
2532 BaseAtom
* target
= this->findAtomByName(it
->realName
);
2533 if ( (target
!= NULL
) && target
->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn
)
2534 fAtoms
.push_back(new SymbolAliasAtom
<A
>(it
->alias
, NULL
, *target
));
2537 // add dtrace probe locations
2538 if ( fHasDTraceProbes
) {
2539 for (uint32_t i
=0; i
< fSymbolCount
; ++i
) {
2540 const macho_nlist
<P
>& sym
= fSymbols
[i
];
2541 if ( (sym
.n_type() & N_STAB
) == 0 ) {
2542 if ( (sym
.n_type() & N_TYPE
) == N_SECT
) {
2543 const char* symbolName
= &fStrings
[sym
.n_strx()];
2544 if ( strncmp(symbolName
, "__dtrace_probe$", 15) == 0 ) {
2545 //fprintf(stderr, "adding dtrace probe at 0x%08llX %s\n", sym.n_value(), symbolName);
2546 makeByNameReference(A::kDtraceProbe
, sym
.n_value(), symbolName
, 0);
2553 // turn indirect symbols into SymbolAliasAtom
2554 if ( fHaveIndirectSymbols
) {
2555 for (uint32_t i
=0; i
< fSymbolCount
; ++i
) {
2556 const macho_nlist
<P
>& sym
= fSymbols
[i
];
2557 if ( (sym
.n_type() & N_STAB
) == 0 ) {
2558 if ( (sym
.n_type() & N_TYPE
) == N_INDR
) {
2559 const char* aliasName
= &fStrings
[sym
.n_strx()];
2560 const char* targetName
= &fStrings
[sym
.n_value()];
2561 //fprintf(stderr, "found alias %s for %s\n", aliasName, targetName);
2562 BaseAtom
* target
= this->findAtomByName(targetName
);
2563 // only currently support N_INDR based aliases to something in the same .o file
2564 if ( target
!= NULL
) {
2565 fAtoms
.push_back(new SymbolAliasAtom
<A
>(aliasName
, &sym
, *target
));
2566 //fprintf(stderr, "creating alias %s for %s\n", aliasName, targetName);
2573 //for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
2574 // fprintf(stderr, "[0x%0X -> 0x%0llX) : %s\n", it->first, it->first+it->second->getSize(), it->second->getDisplayName());
2577 // add translation unit info from dwarf
2579 if ( (fDebugInfo
== kDebugInfoDwarf
) && (fOptions
.fDebugInfoStripping
!= ObjectFile::ReaderOptions::kDebugInfoNone
) ) {
2580 // compiler sometimes emits emtpty dwarf sections when there is no debug info, skip those
2581 if ( (fDwarfDebugInfoSect
!= NULL
) && (fDwarfDebugInfoSect
->size() != 0) ) {
2582 if ( !read_comp_unit(&fDwarfTranslationUnitFile
, &fDwarfTranslationUnitDir
, &stmtList
) ) {
2583 // if can't parse dwarf, warn and give up
2584 fDwarfTranslationUnitFile
= NULL
;
2585 fDwarfTranslationUnitDir
= NULL
;
2586 warning("can't parse dwarf compilation unit info in %s", this->getPath());
2587 fDebugInfo
= kDebugInfoNone
;
2592 // add line number info to atoms from dwarf
2593 if ( (fDebugInfo
== kDebugInfoDwarf
) && (fOptions
.fDebugInfoStripping
!= ObjectFile::ReaderOptions::kDebugInfoNone
) ) {
2594 // file with just data will have no __debug_line info
2595 if ( (fDwarfDebugLineSect
!= NULL
) && (fDwarfDebugLineSect
->size() != 0) && (fAddrToAtom
.size() != 0)
2596 && (fDwarfDebugInfoSect
!= NULL
) && (fDwarfDebugInfoSect
->size() != 0) ) {
2597 // validate stmt_list
2598 if ( (stmtList
!= (uint64_t)-1) && (stmtList
< fDwarfDebugLineSect
->size()) ) {
2599 const uint8_t* debug_line
= (uint8_t*)(fHeader
) + fDwarfDebugLineSect
->offset();
2600 if ( debug_line
!= NULL
) {
2601 struct line_reader_data
* lines
= line_open(&debug_line
[stmtList
],
2602 fDwarfDebugLineSect
->size() - stmtList
, E::little_endian
);
2603 struct line_info result
;
2604 ObjectFile::Atom
* curAtom
= NULL
;
2605 uint32_t curAtomOffset
= 0;
2606 uint32_t curAtomAddress
= 0;
2607 uint32_t curAtomSize
= 0;
2608 if ( lines
!= NULL
) {
2609 while ( line_next (lines
, &result
, line_stop_pc
) ) {
2610 //fprintf(stderr, "curAtom=%p, result.pc=0x%llX, result.line=%llu, result.end_of_sequence=%d, curAtomAddress=0x%X, curAtomSize=0x%X\n",
2611 // curAtom, result.pc, result.line, result.end_of_sequence, curAtomAddress, curAtomSize);
2612 // work around weird debug line table compiler generates if no functions in __text section
2613 if ( (curAtom
== NULL
) && (result
.pc
== 0) && result
.end_of_sequence
&& (result
.file
== 1))
2615 // for performance, see if in next pc is in current atom
2616 if ( (curAtom
!= NULL
) && (curAtomAddress
<= result
.pc
) && (result
.pc
< (curAtomAddress
+curAtomSize
)) ) {
2617 curAtomOffset
= result
.pc
- curAtomAddress
;
2619 // or pc at end of current atom
2620 else if ( result
.end_of_sequence
&& (curAtom
!= NULL
) && (result
.pc
== (curAtomAddress
+curAtomSize
)) ) {
2621 curAtomOffset
= result
.pc
- curAtomAddress
;
2624 // do slow look up of atom by address
2625 AtomAndOffset ao
= this->findAtomAndOffset(result
.pc
);
2627 if ( curAtom
== NULL
)
2628 break; // file has line info but no functions
2629 if ( result
.end_of_sequence
&& (curAtomAddress
+curAtomSize
< result
.pc
) ) {
2630 // a one line function can be returned by line_next() as one entry with pc at end of blob
2631 // look for alt atom starting at end of previous atom
2632 uint32_t previousEnd
= curAtomAddress
+curAtomSize
;
2633 AtomAndOffset alt
= this->findAtomAndOffset(previousEnd
);
2634 if ( result
.pc
<= previousEnd
- alt
.offset
+ alt
.atom
->getSize() ) {
2636 curAtomOffset
= alt
.offset
;
2637 curAtomAddress
= previousEnd
- alt
.offset
;
2638 curAtomSize
= curAtom
->getSize();
2641 curAtomOffset
= ao
.offset
;
2642 curAtomAddress
= result
.pc
- ao
.offset
;
2643 curAtomSize
= curAtom
->getSize();
2647 curAtomOffset
= ao
.offset
;
2648 curAtomAddress
= result
.pc
- ao
.offset
;
2649 curAtomSize
= curAtom
->getSize();
2652 const char* filename
;
2653 std::map
<uint32_t,const char*>::iterator pos
= fDwarfIndexToFile
.find(result
.file
);
2654 if ( pos
== fDwarfIndexToFile
.end() ) {
2655 filename
= line_file(lines
, result
.file
);
2656 fDwarfIndexToFile
[result
.file
] = filename
;
2659 filename
= pos
->second
;
2661 ObjectFile::LineInfo info
;
2662 info
.atomOffset
= curAtomOffset
;
2663 info
.fileName
= filename
;
2664 info
.lineNumber
= result
.line
;
2665 //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n",
2666 // result.pc, result.line, filename, curAtom->getDisplayName(), curAtomSize, result.end_of_sequence);
2667 ((BaseAtom
*)curAtom
)->addLineInfo(info
);
2668 if ( result
.end_of_sequence
) {
2676 warning("could not parse dwarf line number info in %s", this->getPath());
2682 // if no dwarf, try processing stabs debugging info
2683 if ( (fDebugInfo
== kDebugInfoNone
) && (fOptions
.fDebugInfoStripping
!= ObjectFile::ReaderOptions::kDebugInfoNone
) ) {
2684 // scan symbol table for stabs entries
2685 fStabs
.reserve(fSymbolCount
); // reduce re-allocations
2686 BaseAtom
* currentAtom
= NULL
;
2687 pint_t currentAtomAddress
= 0;
2688 enum { start
, inBeginEnd
, inFun
} state
= start
;
2689 for (uint32_t symbolIndex
= 0; symbolIndex
< fSymbolCount
; ++symbolIndex
) {
2690 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2691 bool useStab
= true;
2692 uint8_t type
= sym
->n_type();
2693 const char* symString
= (sym
->n_strx() != 0) ? &fStrings
[sym
->n_strx()] : NULL
;
2694 if ( (type
& N_STAB
) != 0 ) {
2695 fDebugInfo
= (fHasUUID
? kDebugInfoStabsUUID
: kDebugInfoStabs
);
2699 stab
.other
= sym
->n_sect();
2700 stab
.desc
= sym
->n_desc();
2701 stab
.value
= sym
->n_value();
2707 // beginning of function block
2709 // fall into case to lookup atom by addresss
2712 currentAtomAddress
= sym
->n_value();
2713 currentAtom
= (BaseAtom
*)this->findAtomAndOffset(currentAtomAddress
).atom
;
2714 if ( currentAtom
!= NULL
) {
2715 stab
.atom
= currentAtom
;
2716 stab
.string
= symString
;
2719 fprintf(stderr
, "can't find atom for stabs BNSYM at %08llX in %s",
2720 (uint64_t)sym
->n_value(), path
);
2729 // not associated with an atom, just copy
2730 stab
.string
= symString
;
2734 // n_value field is NOT atom address ;-(
2735 // need to find atom by name match
2736 const char* colon
= strchr(symString
, ':');
2737 if ( colon
!= NULL
) {
2738 // build underscore leading name
2739 int nameLen
= colon
- symString
;
2740 char symName
[nameLen
+2];
2741 strlcpy(&symName
[1], symString
, nameLen
+1);
2743 symName
[nameLen
+1] = '\0';
2744 currentAtom
= findAtomByName(symName
);
2745 if ( currentAtom
!= NULL
) {
2746 stab
.atom
= currentAtom
;
2747 stab
.string
= symString
;
2751 // might be a debug-note without trailing :G()
2752 currentAtom
= findAtomByName(symString
);
2753 if ( currentAtom
!= NULL
) {
2754 stab
.atom
= currentAtom
;
2755 stab
.string
= symString
;
2758 if ( stab
.atom
== NULL
) {
2759 // ld_classic added bogus GSYM stabs for old style dtrace probes
2760 if ( (strncmp(symString
, "__dtrace_probe$", 15) != 0) )
2761 warning("can't find atom for N_GSYM stabs %s in %s", symString
, path
);
2767 // old style stabs without BNSYM
2769 currentAtomAddress
= sym
->n_value();
2770 currentAtom
= (BaseAtom
*)this->findAtomAndOffset(currentAtomAddress
).atom
;
2771 if ( currentAtom
!= NULL
) {
2772 stab
.atom
= currentAtom
;
2773 stab
.string
= symString
;
2776 warning("can't find atom for stabs FUN at %08llX in %s",
2777 (uint64_t)currentAtomAddress
, path
);
2782 stab
.string
= symString
;
2788 stab
.string
= symString
;
2789 // -gfull built .o file
2792 warning("unknown stabs type 0x%X in %s", type
, path
);
2796 stab
.atom
= currentAtom
;
2805 BaseAtom
* nestedAtom
= (BaseAtom
*)this->findAtomAndOffset(sym
->n_value()).atom
;
2806 if ( nestedAtom
!= NULL
) {
2807 stab
.atom
= nestedAtom
;
2808 stab
.string
= symString
;
2811 warning("can't find atom for stabs 0x%X at %08llX in %s",
2812 type
, (uint64_t)sym
->n_value(), path
);
2819 // adjust value to be offset in atom
2820 stab
.value
-= currentAtomAddress
;
2822 stab
.string
= symString
;
2829 if ( sym
->n_sect() != 0 ) {
2830 // found another start stab, must be really old stabs...
2831 currentAtomAddress
= sym
->n_value();
2832 currentAtom
= (BaseAtom
*)this->findAtomAndOffset(currentAtomAddress
).atom
;
2833 if ( currentAtom
!= NULL
) {
2834 stab
.atom
= currentAtom
;
2835 stab
.string
= symString
;
2838 warning("can't find atom for stabs FUN at %08llX in %s",
2839 (uint64_t)currentAtomAddress
, path
);
2843 // found ending stab, switch back to start state
2844 stab
.string
= symString
;
2845 stab
.atom
= currentAtom
;
2853 // adjust value to be offset in atom
2854 stab
.value
-= currentAtomAddress
;
2855 stab
.atom
= currentAtom
;
2858 stab
.string
= symString
;
2862 stab
.atom
= currentAtom
;
2863 stab
.string
= symString
;
2868 // add to list of stabs for this .o file
2870 fStabs
.push_back(stab
);
2876 // special case precompiled header .o file (which has no content) to have one empty atom
2877 if ( fAtoms
.size() == 0 ) {
2878 int pathLen
= strlen(path
);
2879 if ( (pathLen
> 6) && (strcmp(&path
[pathLen
-6], ".gch.o")==0) ) {
2880 ObjectFile::Atom
* phony
= new AnonymousAtom
<A
>(*this, (uint32_t)0);
2881 //phony->fSynthesizedName = ".gch.o";
2882 fAtoms
.push_back(phony
);
2887 // sort all atoms by address
2888 std::sort(fAtoms
.begin(), fAtoms
.end(), BaseAtomSorter());
2890 // set ordinal and sort references in each atom
2891 uint32_t index
= fOrdinalBase
;
2892 for (std::vector
<BaseAtom
*>::iterator it
=fAtoms
.begin(); it
!= fAtoms
.end(); it
++) {
2893 BaseAtom
* atom
= (BaseAtom
*)(*it
);
2894 atom
->setOrdinal(index
++);
2895 atom
->sortReferences();
2900 template <typename A
>
2901 const macho_section
<typename
A::P
>* Reader
<A
>::getSectionForAddress(pint_t addr
)
2903 for (const macho_section
<P
>* sect
=fSectionsStart
; sect
< fSectionsEnd
; ++sect
) {
2904 if ( (sect
->addr() <= addr
) && (addr
< (sect
->addr()+sect
->size())) )
2907 throwf("section not found for address 0x%08llX", (uint64_t)addr
);
2910 template <typename A
>
2911 ObjectFile::Atom
* Reader
<A
>::getFunctionAtomFromFDEAddress(pint_t addr
)
2913 for (typename
std::vector
<FDE_Atom_Info
>::const_iterator it
= fFDEInfos
.begin(); it
!= fFDEInfos
.end(); ++it
) {
2914 if ( it
->fdeAddress
== addr
) {
2915 return findAtomAndOffset(it
->function
.address
).atom
;
2918 // CIEs won't be in fFDEInfos
2922 template <typename A
>
2923 ObjectFile::Atom
* Reader
<A
>::getFunctionAtomFromLSDAAddress(pint_t addr
)
2925 for (typename
std::vector
<FDE_Atom_Info
>::const_iterator it
= fFDEInfos
.begin(); it
!= fFDEInfos
.end(); ++it
) {
2926 if ( it
->lsda
.address
== addr
) {
2927 return findAtomAndOffset(it
->function
.address
).atom
;
2935 void ObjectFileAddressSpace
<x86_64
>::buildRelocatedMap(const macho_section
<P
>* sect
, std::map
<uint32_t,uint64_t>& map
)
2937 // mach-o x86_64 is different, the content of a section with a relocation is the addend
2938 const macho_relocation_info
<P
>* relocs
= (macho_relocation_info
<P
>*)((char*)(fReader
.fHeader
) + sect
->reloff());
2939 const macho_relocation_info
<P
>* relocsEnd
= &relocs
[sect
->nreloc()];
2940 for (const macho_relocation_info
<P
>* reloc
= relocs
; reloc
< relocsEnd
; ++reloc
) {
2941 std::map
<uint32_t,uint64_t>::iterator pos
;
2942 switch ( reloc
->r_type() ) {
2943 case X86_64_RELOC_UNSIGNED
:
2944 pos
= map
.find(reloc
->r_address());
2945 if ( pos
!= map
.end() )
2946 pos
->second
+= fReader
.fSymbols
[reloc
->r_symbolnum()].n_value();
2948 map
[reloc
->r_address()] = fReader
.fSymbols
[reloc
->r_symbolnum()].n_value();
2950 case X86_64_RELOC_SUBTRACTOR
:
2951 map
[reloc
->r_address()] = -fReader
.fSymbols
[reloc
->r_symbolnum()].n_value();
2953 case X86_64_RELOC_GOT
:
2954 // there is no good address to return here.
2955 // GOT slots are synthsized by the linker
2956 // this is used for the reference to the personality function in CIEs
2957 map
[reloc
->r_address()] = 0;
2960 fprintf(stderr
, "ObjectFileAddressSpace::buildRelocatedMap() unexpected relocation at r_address=0x%08X\n", reloc
->r_address());
2966 template <typename A
>
2967 void ObjectFileAddressSpace
<A
>::buildRelocatedMap(const macho_section
<P
>* sect
, std::map
<uint32_t,uint64_t>& map
)
2969 // in all architectures except x86_64, the section contents are already fixed up to point
2970 // to content in the same object file.
2974 uint64_t ObjectFileAddressSpace
<x86_64
>::relocated(uint32_t sectOffset
, uint32_t relocsOffset
, uint32_t relocsCount
)
2976 // mach-o x86_64 is different, the content of a section with a relocation is the addend
2977 uint64_t result
= 0;
2978 const macho_relocation_info
<P
>* relocs
= (macho_relocation_info
<P
>*)((char*)(fReader
.fHeader
) + relocsOffset
);
2979 const macho_relocation_info
<P
>* relocsEnd
= &relocs
[relocsCount
];
2980 for (const macho_relocation_info
<P
>* reloc
= relocs
; reloc
< relocsEnd
; ++reloc
) {
2981 //fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X), r_address=0x%08X\n", sectOffset, reloc->r_address());
2982 if ( reloc
->r_address() == sectOffset
) {
2983 switch ( reloc
->r_type() ) {
2984 case X86_64_RELOC_UNSIGNED
:
2985 result
+= fReader
.fSymbols
[reloc
->r_symbolnum()].n_value();
2987 case X86_64_RELOC_SUBTRACTOR
:
2988 result
-= fReader
.fSymbols
[reloc
->r_symbolnum()].n_value();
2990 case X86_64_RELOC_GOT
:
2991 // there is no good address to return here.
2992 // GOT slots are synthsized by the linker
2993 // this is used for the reference to the personality function in CIEs
2997 fprintf(stderr
, "ObjectFileAddressSpace::relocated(0x%08X) => type=%d, value=0x%08X\n", sectOffset
, reloc
->r_type(), reloc
->r_symbolnum());
3002 //fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X) => 0x%0llX\n", sectOffset, result);
3006 template <typename A
>
3007 typename
A::P::uint_t ObjectFileAddressSpace
<A
>::relocated(uint32_t sectOffset
, uint32_t relocsOffset
, uint32_t relocsCount
)
3009 // in all architectures except x86_64, the section contents are already fixed up to point
3010 // to content in the same object file.
3016 // FSF exception handling Pointer-Encoding constants
3017 // Used in CFI augmentation by gcc compiler
3019 DW_EH_PE_ptr
= 0x00,
3020 DW_EH_PE_uleb128
= 0x01,
3021 DW_EH_PE_udata2
= 0x02,
3022 DW_EH_PE_udata4
= 0x03,
3023 DW_EH_PE_udata8
= 0x04,
3024 DW_EH_PE_signed
= 0x08,
3025 DW_EH_PE_sleb128
= 0x09,
3026 DW_EH_PE_sdata2
= 0x0A,
3027 DW_EH_PE_sdata4
= 0x0B,
3028 DW_EH_PE_sdata8
= 0x0C,
3029 DW_EH_PE_absptr
= 0x00,
3030 DW_EH_PE_pcrel
= 0x10,
3031 DW_EH_PE_textrel
= 0x20,
3032 DW_EH_PE_datarel
= 0x30,
3033 DW_EH_PE_funcrel
= 0x40,
3034 DW_EH_PE_aligned
= 0x50,
3035 DW_EH_PE_indirect
= 0x80,
3036 DW_EH_PE_omit
= 0xFF
3040 void Reader
<x86_64
>::addCiePersonalityReference(BaseAtom
* cieAtom
, uint32_t offsetInCIE
, uint8_t encoding
)
3042 if ( encoding
!= (DW_EH_PE_indirect
|DW_EH_PE_pcrel
|DW_EH_PE_sdata4
) )
3043 throw "unexpected personality encoding in CIE";
3045 // walk relocs looking for reloc in this CIE
3046 uint32_t sectOffset
= (cieAtom
->getObjectAddress() + offsetInCIE
) - fehFrameSection
->addr();
3047 const macho_relocation_info
<P
>* relocs
= (macho_relocation_info
<P
>*)((char*)(fHeader
) + fehFrameSection
->reloff());
3048 const macho_relocation_info
<P
>* relocsEnd
= &relocs
[fehFrameSection
->nreloc()];
3049 for (const macho_relocation_info
<P
>* reloc
= relocs
; reloc
< relocsEnd
; ++reloc
) {
3050 if ( reloc
->r_address() == sectOffset
) {
3051 switch ( reloc
->r_type() ) {
3052 case X86_64_RELOC_GOT
:
3053 if ( !reloc
->r_extern() )
3054 throw "GOT reloc not extern for personality function";
3055 new Reference
<x86_64
>(x86_64::kPCRel32GOT
, AtomAndOffset(cieAtom
, offsetInCIE
), &fStrings
[fSymbols
[reloc
->r_symbolnum()].n_strx()], 4);
3058 throw "expected GOT reloc for personality function";
3062 throw "personality function not found for CIE";
3066 bool Reader
<ppc
>::isSectDiffReloc(uint8_t r_type
)
3069 case PPC_RELOC_LOCAL_SECTDIFF
:
3070 case PPC_RELOC_SECTDIFF
:
3077 bool Reader
<ppc64
>::isSectDiffReloc(uint8_t r_type
)
3080 case PPC_RELOC_LOCAL_SECTDIFF
:
3081 case PPC_RELOC_SECTDIFF
:
3088 bool Reader
<x86
>::isSectDiffReloc(uint8_t r_type
)
3091 case GENERIC_RELOC_LOCAL_SECTDIFF
:
3092 case GENERIC_RELOC_SECTDIFF
:
3099 bool Reader
<arm
>::isSectDiffReloc(uint8_t r_type
)
3102 case ARM_RELOC_LOCAL_SECTDIFF
:
3103 case ARM_RELOC_SECTDIFF
:
3109 template <typename A
>
3110 void Reader
<A
>::addCiePersonalityReference(BaseAtom
* cieAtom
, uint32_t offsetInCIE
, uint8_t encoding
)
3112 if ( (encoding
!= (DW_EH_PE_indirect
|DW_EH_PE_pcrel
|DW_EH_PE_sdata4
)) && (encoding
!= (DW_EH_PE_indirect
|DW_EH_PE_pcrel
)) )
3113 throw "unexpected personality encoding in CIE";
3115 // walk relocs looking for personality reloc in this CIE
3116 uint32_t sectOffset
= (cieAtom
->getObjectAddress() + offsetInCIE
) - fehFrameSection
->addr();
3117 const macho_relocation_info
<P
>* relocs
= (macho_relocation_info
<P
>*)((char*)(fHeader
) + fehFrameSection
->reloff());
3118 const macho_relocation_info
<P
>* relocsEnd
= &relocs
[fehFrameSection
->nreloc()];
3119 for (const macho_relocation_info
<P
>* reloc
= relocs
; reloc
< relocsEnd
; ++reloc
) {
3120 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
3124 const macho_scattered_relocation_info
<P
>* sreloc
= (macho_scattered_relocation_info
<P
>*)reloc
;
3125 if ( sreloc
->r_address() == sectOffset
) {
3126 if ( isSectDiffReloc(sreloc
->r_type()) ) {
3127 // r_value is address of non-lazy-pointer to personality function
3128 new Reference
<A
>(A::kPointerDiff32
, AtomAndOffset(cieAtom
, offsetInCIE
), AtomAndOffset(cieAtom
, offsetInCIE
),
3129 findAtomAndOffset(sreloc
->r_value()));
3135 throw "can't find relocation for personality in CIE";
3138 template <typename A
>
3139 void Reader
<A
>::addFdeReference(uint8_t encoding
, AtomAndOffset inFDE
, AtomAndOffset target
)
3141 if ( (encoding
& 0xF0) != DW_EH_PE_pcrel
)
3142 throw "unsupported encoding in FDE";
3143 Kinds kind
= A::kNoFixUp
;
3144 switch ( encoding
& 0xF ) {
3146 kind
= A::kPointerDiff
;
3148 case DW_EH_PE_sdata4
:
3149 kind
= A::kPointerDiff32
;
3152 throw "unsupported encoding in FDE";
3154 new Reference
<A
>(kind
, inFDE
, inFDE
, target
);
3157 template <typename A
>
3158 typename
A::P::uint_t ObjectFileAddressSpace
<A
>::getEncodedP(pint_t
& addr
, pint_t end
, uint8_t encoding
)
3160 pint_t startAddr
= addr
;
3165 switch (encoding
& 0x0F) {
3167 result
= getP(addr
);
3168 p
+= sizeof(pint_t
);
3171 case DW_EH_PE_uleb128
:
3172 result
= getULEB128(addr
, end
);
3174 case DW_EH_PE_udata2
:
3175 result
= get16(addr
);
3179 case DW_EH_PE_udata4
:
3180 result
= get32(addr
);
3184 case DW_EH_PE_udata8
:
3185 result
= get64(addr
);
3189 case DW_EH_PE_sleb128
:
3190 result
= getSLEB128(addr
, end
);
3192 case DW_EH_PE_sdata2
:
3193 result
= (int16_t)get16(addr
);
3197 case DW_EH_PE_sdata4
:
3198 result
= (int32_t)get32(addr
);
3202 case DW_EH_PE_sdata8
:
3203 result
= get64(addr
);
3208 throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding
);
3211 // then add relative offset
3212 switch ( encoding
& 0x70 ) {
3213 case DW_EH_PE_absptr
:
3216 case DW_EH_PE_pcrel
:
3217 result
+= startAddr
;
3219 case DW_EH_PE_textrel
:
3220 throw "DW_EH_PE_textrel pointer encoding not supported";
3222 case DW_EH_PE_datarel
:
3223 throw "DW_EH_PE_datarel pointer encoding not supported";
3225 case DW_EH_PE_funcrel
:
3226 throw "DW_EH_PE_funcrel pointer encoding not supported";
3228 case DW_EH_PE_aligned
:
3229 throw "DW_EH_PE_aligned pointer encoding not supported";
3232 throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding
);
3236 if ( encoding
& DW_EH_PE_indirect
)
3237 result
= getP(result
);
3243 uint32_t SymbolAtom
<x86
>::getCompactUnwindEncoding(uint64_t ehAtomAddress
)
3247 char warningBuffer
[1024];
3248 uint32_t result
= libunwind::DwarfInstructions
<class ObjectFileAddressSpace
<x86
>, libunwind::Registers_x86
>::createCompactEncodingFromFDE(
3249 fOwner
.fObjectAddressSpace
, ehAtomAddress
, &lsda
, &personality
, warningBuffer
);
3250 if ( (result
& UNWIND_X86_MODE_MASK
) == UNWIND_X86_MODE_DWARF
) {
3251 //if ( fOwner.fOptions.fForDyld )
3252 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3254 if ( fOwner
.fOptions
.fWarnCompactUnwind
)
3255 warning("can't make compact unwind encoding from dwarf for %s in %s because %s", this->getDisplayName(), fOwner
.getPath(), warningBuffer
);
3261 uint32_t SymbolAtom
<x86_64
>::getCompactUnwindEncoding(uint64_t ehAtomAddress
)
3265 char warningBuffer
[1024];
3266 uint32_t result
= libunwind::DwarfInstructions
<class ObjectFileAddressSpace
<x86_64
>, libunwind::Registers_x86_64
>::createCompactEncodingFromFDE(
3267 fOwner
.fObjectAddressSpace
, ehAtomAddress
, &lsda
, &personality
, warningBuffer
);
3268 if ( (result
& UNWIND_X86_64_MODE_MASK
) == UNWIND_X86_64_MODE_DWARF
) {
3269 //if ( fOwner.fOptions.fForDyld )
3270 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3272 if ( fOwner
.fOptions
.fWarnCompactUnwind
)
3273 warning("can't make compact unwind encoding from dwarf for %s in %s because %s", this->getDisplayName(), fOwner
.getPath(), warningBuffer
);
3279 uint32_t SymbolAtom
<ppc
>::getCompactUnwindEncoding(uint64_t ehAtomAddress
)
3281 // compact encoding not supported for ppc
3286 uint32_t SymbolAtom
<ppc64
>::getCompactUnwindEncoding(uint64_t ehAtomAddress
)
3288 // compact encoding not supported for ppc64
3293 uint32_t SymbolAtom
<arm
>::getCompactUnwindEncoding(uint64_t ehAtomAddress
)
3295 // compact encoding not supported for arm
3300 template <typename A
>
3301 uint8_t SymbolAtom
<A
>::getLSDAReferenceKind() const
3303 return A::kGroupSubordinate
;
3307 uint8_t SymbolAtom
<x86_64
>::getPersonalityReferenceKind() const
3309 return x86_64::kGOTNoFixUp
;
3313 uint8_t SymbolAtom
<x86
>::getPersonalityReferenceKind() const
3315 return x86::kNoFixUp
;
3318 template <typename A
>
3319 uint8_t SymbolAtom
<A
>::getPersonalityReferenceKind() const
3321 // only used with architectures that support compact unwinding
3327 uint32_t AnonymousAtom
<x86
>::getCompactUnwindEncoding(uint64_t ehAtomAddress
)
3331 char warningBuffer
[1024];
3332 uint32_t result
= libunwind::DwarfInstructions
<class ObjectFileAddressSpace
<x86
>, libunwind::Registers_x86
>::createCompactEncodingFromFDE(
3333 fOwner
.fObjectAddressSpace
, ehAtomAddress
, &lsda
, &personality
, warningBuffer
);
3334 if ( (result
& UNWIND_X86_MODE_MASK
) == UNWIND_X86_MODE_DWARF
) {
3335 //if ( fOwner.fOptions.fForDyld )
3336 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3338 if ( fOwner
.fOptions
.fWarnCompactUnwind
)
3339 warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner
.getPath());
3345 uint32_t AnonymousAtom
<x86_64
>::getCompactUnwindEncoding(uint64_t ehAtomAddress
)
3349 char warningBuffer
[1024];
3350 uint32_t result
= libunwind::DwarfInstructions
<class ObjectFileAddressSpace
<x86_64
>, libunwind::Registers_x86_64
>::createCompactEncodingFromFDE(
3351 fOwner
.fObjectAddressSpace
, ehAtomAddress
, &lsda
, &personality
, warningBuffer
);
3352 if ( (result
& UNWIND_X86_64_MODE_MASK
) == UNWIND_X86_64_MODE_DWARF
) {
3353 //if ( fOwner.fOptions.fForDyld )
3354 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3356 if ( fOwner
.fOptions
.fWarnCompactUnwind
)
3357 warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner
.getPath());
3363 uint32_t AnonymousAtom
<ppc
>::getCompactUnwindEncoding(uint64_t ehAtomAddress
)
3365 // compact encoding not supported for ppc
3370 uint32_t AnonymousAtom
<ppc64
>::getCompactUnwindEncoding(uint64_t ehAtomAddress
)
3372 // compact encoding not supported for ppc64
3377 uint32_t AnonymousAtom
<arm
>::getCompactUnwindEncoding(uint64_t ehAtomAddress
)
3379 // compact encoding not supported for arm
3384 template <typename A
>
3385 uint8_t AnonymousAtom
<A
>::getLSDAReferenceKind() const
3387 return A::kGroupSubordinate
;
3391 uint8_t AnonymousAtom
<x86_64
>::getPersonalityReferenceKind() const
3393 return x86_64::kGOTNoFixUp
;
3397 uint8_t AnonymousAtom
<x86
>::getPersonalityReferenceKind() const
3399 return x86::kNoFixUp
;
3402 template <typename A
>
3403 uint8_t AnonymousAtom
<A
>::getPersonalityReferenceKind() const
3405 // only used with architectures that support compact unwinding
3416 void Reader
<ppc
>::setCpuConstraint(uint32_t cpusubtype
)
3418 switch (cpusubtype
) {
3419 case CPU_SUBTYPE_POWERPC_ALL
:
3420 case CPU_SUBTYPE_POWERPC_750
:
3421 case CPU_SUBTYPE_POWERPC_7400
:
3422 case CPU_SUBTYPE_POWERPC_7450
:
3423 case CPU_SUBTYPE_POWERPC_970
:
3424 fCpuConstraint
= cpusubtype
;
3427 warning("unknown ppc subtype 0x%08X in %s, defaulting to ALL", cpusubtype
, fPath
);
3428 fCpuConstraint
= CPU_SUBTYPE_POWERPC_ALL
;
3434 void Reader
<arm
>::setCpuConstraint(uint32_t cpusubtype
)
3436 switch (cpusubtype
) {
3437 case CPU_SUBTYPE_ARM_ALL
:
3438 case CPU_SUBTYPE_ARM_V4T
:
3439 case CPU_SUBTYPE_ARM_V5TEJ
:
3440 case CPU_SUBTYPE_ARM_V6
:
3441 case CPU_SUBTYPE_ARM_XSCALE
:
3442 case CPU_SUBTYPE_ARM_V7
:
3443 fCpuConstraint
= cpusubtype
;
3446 warning("unknown arm subtype 0x%08X in %s, defaulting to ALL", cpusubtype
, fPath
);
3447 fCpuConstraint
= CPU_SUBTYPE_ARM_ALL
;
3452 template <typename A
>
3453 void Reader
<A
>::setCpuConstraint(uint32_t cpusubtype
)
3455 // no cpu sub types for this architecture
3459 uint32_t Reader
<ppc
>::updateCpuConstraint(uint32_t previous
)
3461 switch ( previous
) {
3462 case CPU_SUBTYPE_POWERPC_ALL
:
3463 return fCpuConstraint
;
3465 case CPU_SUBTYPE_POWERPC_750
:
3466 if ( fCpuConstraint
== CPU_SUBTYPE_POWERPC_7400
||
3467 fCpuConstraint
== CPU_SUBTYPE_POWERPC_7450
||
3468 fCpuConstraint
== CPU_SUBTYPE_POWERPC_970
)
3469 return fCpuConstraint
;
3471 case CPU_SUBTYPE_POWERPC_7400
:
3472 case CPU_SUBTYPE_POWERPC_7450
:
3473 if ( fCpuConstraint
== CPU_SUBTYPE_POWERPC_970
)
3474 return fCpuConstraint
;
3476 case CPU_SUBTYPE_POWERPC_970
:
3477 // G5 can run everything
3480 throw "Unhandled PPC cpu subtype!";
3489 uint32_t Reader
<arm
>::updateCpuConstraint(uint32_t previous
)
3492 case CPU_SUBTYPE_ARM_ALL
:
3493 return fCpuConstraint
;
3495 case CPU_SUBTYPE_ARM_V5TEJ
:
3496 // v6, v7, and xscale are more constrained than previous file (v5), so use it
3497 if ( (fCpuConstraint
== CPU_SUBTYPE_ARM_V6
)
3498 || (fCpuConstraint
== CPU_SUBTYPE_ARM_V7
)
3499 || (fCpuConstraint
== CPU_SUBTYPE_ARM_XSCALE
) )
3500 return fCpuConstraint
;
3502 case CPU_SUBTYPE_ARM_V4T
:
3503 // v5, v6, v7, and xscale are more constrained than previous file (v4t), so use it
3504 if ( (fCpuConstraint
== CPU_SUBTYPE_ARM_V7
)
3505 || (fCpuConstraint
== CPU_SUBTYPE_ARM_V6
)
3506 || (fCpuConstraint
== CPU_SUBTYPE_ARM_V5TEJ
)
3507 || (fCpuConstraint
== CPU_SUBTYPE_ARM_XSCALE
) )
3508 return fCpuConstraint
;
3510 case CPU_SUBTYPE_ARM_V6
:
3511 // v6 can run everything except xscale and v7
3512 if ( fCpuConstraint
== CPU_SUBTYPE_ARM_XSCALE
)
3513 throw "can't mix xscale and v6 code";
3514 if ( fCpuConstraint
== CPU_SUBTYPE_ARM_V7
)
3515 return fCpuConstraint
;
3517 case CPU_SUBTYPE_ARM_XSCALE
:
3518 // xscale can run everything except v6 and v7
3519 if ( fCpuConstraint
== CPU_SUBTYPE_ARM_V6
)
3520 throw "can't mix xscale and v6 code";
3521 if ( fCpuConstraint
== CPU_SUBTYPE_ARM_V7
)
3522 throw "can't mix xscale and v7 code";
3524 case CPU_SUBTYPE_ARM_V7
:
3525 // v7 can run everything except xscale
3526 if ( fCpuConstraint
== CPU_SUBTYPE_ARM_XSCALE
)
3527 throw "can't mix xscale and v7 code";
3530 throw "Unhandled ARM cpu subtype!";
3535 template <typename A
>
3536 uint32_t Reader
<A
>::updateCpuConstraint(uint32_t current
)
3538 // no cpu sub types for this architecture
3542 template <typename A
>
3543 void Reader
<A
>::addDtraceExtraInfos(uint32_t probeAddr
, const char* providerName
)
3545 // for every ___dtrace_stability$* and ___dtrace_typedefs$* undefine with
3546 // a matching provider name, add a by-name kDtraceTypeReference at probe site
3547 const char* dollar
= strchr(providerName
, '$');
3548 if ( dollar
!= NULL
) {
3549 int providerNameLen
= dollar
-providerName
+1;
3550 for ( std::vector
<const char*>::iterator it
= fDtraceProviderInfo
.begin(); it
!= fDtraceProviderInfo
.end(); ++it
) {
3551 const char* typeDollar
= strchr(*it
, '$');
3552 if ( typeDollar
!= NULL
) {
3553 if ( strncmp(typeDollar
+1, providerName
, providerNameLen
) == 0 ) {
3554 makeByNameReference(A::kDtraceTypeReference
, probeAddr
, *it
, 0);
3563 void Reader
<x86_64
>::validSectionType(uint8_t type
)
3566 case S_SYMBOL_STUBS
:
3567 throw "symbol_stub sections not valid in x86_64 object files";
3568 case S_LAZY_SYMBOL_POINTERS
:
3569 throw "lazy pointer sections not valid in x86_64 object files";
3570 case S_NON_LAZY_SYMBOL_POINTERS
:
3571 throw "non lazy pointer sections not valid in x86_64 object files";
3575 template <typename A
>
3576 void Reader
<A
>::validSectionType(uint8_t type
)
3580 template <typename A
>
3581 bool Reader
<A
>::getTranslationUnitSource(const char** dir
, const char** name
) const
3583 if ( fDebugInfo
== kDebugInfoDwarf
) {
3584 *dir
= fDwarfTranslationUnitDir
;
3585 *name
= fDwarfTranslationUnitFile
;
3586 return (fDwarfTranslationUnitFile
!= NULL
);
3591 template <typename A
>
3592 BaseAtom
* Reader
<A
>::findAtomByName(const char* name
)
3594 // first search the more important atoms
3595 for (typename
AddrToAtomMap::iterator it
=fAddrToAtom
.begin(); it
!= fAddrToAtom
.end(); it
++) {
3596 const char* atomName
= it
->second
->getName();
3597 if ( (atomName
!= NULL
) && (strcmp(atomName
, name
) == 0) ) {
3601 // try all atoms, because this might have been a tentative definition
3602 for (std::vector
<BaseAtom
*>::iterator it
=fAtoms
.begin(); it
!= fAtoms
.end(); it
++) {
3603 BaseAtom
* atom
= (BaseAtom
*)(*it
);
3604 const char* atomName
= atom
->getName();
3605 if ( (atomName
!= NULL
) && (strcmp(atomName
, name
) == 0) ) {
3612 template <typename A
>
3613 Reference
<A
>* Reader
<A
>::makeReference(Kinds kind
, pint_t atAddr
, pint_t toAddr
)
3615 return new Reference
<A
>(kind
, findAtomAndOffset(atAddr
), findAtomAndOffset(toAddr
));
3618 template <typename A
>
3619 Reference
<A
>* Reader
<A
>::makeReference(Kinds kind
, pint_t atAddr
, pint_t fromAddr
, pint_t toAddr
)
3621 return new Reference
<A
>(kind
, findAtomAndOffset(atAddr
), findAtomAndOffset(fromAddr
), findAtomAndOffset(toAddr
));
3624 template <typename A
>
3625 Reference
<A
>* Reader
<A
>::makeReferenceWithToBase(Kinds kind
, pint_t atAddr
, pint_t toAddr
, pint_t toBaseAddr
)
3627 return new Reference
<A
>(kind
, findAtomAndOffset(atAddr
), findAtomAndOffset(toBaseAddr
, toAddr
));
3630 template <typename A
>
3631 Reference
<A
>* Reader
<A
>::makeReferenceWithToBase(Kinds kind
, pint_t atAddr
, pint_t fromAddr
, pint_t toAddr
, pint_t toBaseAddr
)
3633 return new Reference
<A
>(kind
, findAtomAndOffset(atAddr
), findAtomAndOffset(fromAddr
), findAtomAndOffset(toBaseAddr
, toAddr
));
3636 template <typename A
>
3637 Reference
<A
>* Reader
<A
>::makeByNameReference(Kinds kind
, pint_t atAddr
, const char* toName
, uint32_t toOffset
)
3639 return new Reference
<A
>(kind
, findAtomAndOffset(atAddr
), toName
, toOffset
);
3642 template <typename A
>
3643 BaseAtom
* Reader
<A
>::makeReferenceToEH(const char* ehName
, pint_t ehAtomAddress
, const macho_section
<P
>* ehSect
)
3645 // add a group subordinate reference from function atom to its eh frame atom
3646 const uint8_t* ehContent
= (const uint8_t*)(fHeader
) + ehAtomAddress
- ehSect
->addr() + ehSect
->offset();
3647 int32_t deltaMinus8
= P::getP(*(pint_t
*)(&ehContent
[8])); // offset 8 in eh info is delta to function
3648 pint_t funcAddr
= ehAtomAddress
+ deltaMinus8
+ 8;
3649 ObjectFile::Atom
* funcAtom
= findAtomAndOffset(funcAddr
).atom
;
3650 ObjectFile::Atom
* ehAtom
= findAtomAndOffset(ehAtomAddress
).atom
;
3651 new Reference
<A
>(A::kGroupSubordinate
, funcAtom
, ehAtom
);
3652 return (BaseAtom
*)funcAtom
;
3657 Reference
<x86_64
>* Reader
<x86_64
>::makeByNameReference(Kinds kind
, pint_t atAddr
, const char* toName
, uint32_t toOffset
)
3659 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
3660 // instead check scope of target
3661 BaseAtom
* target
= findAtomByName(toName
);
3662 if ( (target
!= NULL
) && (target
->getScope() == ObjectFile::Atom::scopeTranslationUnit
) )
3663 return new Reference
<x86_64
>(kind
, findAtomAndOffset(atAddr
), AtomAndOffset(target
, toOffset
));
3665 return new Reference
<x86_64
>(kind
, findAtomAndOffset(atAddr
), toName
, toOffset
);
3669 Reference
<x86_64
>* Reader
<x86_64
>::makeReferenceToSymbol(Kinds kind
, pint_t atAddr
, const macho_nlist
<P
>* toSymbol
, pint_t toOffset
)
3671 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
3672 // instead check scope of target
3673 const char* symbolName
= &fStrings
[toSymbol
->n_strx()];
3674 if ( ((toSymbol
->n_type() & N_TYPE
) == N_SECT
) && (((toSymbol
->n_type() & N_EXT
) == 0) || (symbolName
[0] == 'L')) ) {
3675 AtomAndOffset targetAO
= findAtomAndOffsetForSection(toSymbol
->n_value(), toSymbol
->n_sect());
3676 targetAO
.offset
= toOffset
;
3677 return new Reference
<x86_64
>(kind
, findAtomAndOffset(atAddr
), targetAO
);
3680 return new Reference
<x86_64
>(kind
, findAtomAndOffset(atAddr
), symbolName
, toOffset
);
3685 BaseAtom
* Reader
<x86_64
>::makeReferenceToEH(const char* ehName
, pint_t ehAtomAddress
, const macho_section
<P
>* ehSect
)
3687 // add a group subordinate reference from function atom to its eh frame atom
3688 // for x86_64 the __eh_frame section contains the addends, so need to use relocs to find target
3689 uint32_t ehAtomDeltaSectionOffset
= ehAtomAddress
+ 8 - ehSect
->addr(); // offset 8 in eh info is delta to function
3690 const macho_relocation_info
<P
>* relocs
= (macho_relocation_info
<P
>*)((char*)(fHeader
) + ehSect
->reloff());
3691 const macho_relocation_info
<P
>* relocsEnd
= &relocs
[ehSect
->nreloc()];
3692 for (const macho_relocation_info
<P
>* reloc
= relocs
; reloc
< relocsEnd
; ++reloc
) {
3693 if ( (reloc
->r_address() == ehAtomDeltaSectionOffset
) && (reloc
->r_type() == X86_64_RELOC_UNSIGNED
) ) {
3694 pint_t funcAddr
= fSymbols
[reloc
->r_symbolnum()].n_value();
3695 ObjectFile::Atom
* funcAtom
= findAtomAndOffset(funcAddr
).atom
;
3696 ObjectFile::Atom
* ehAtom
= findAtomAndOffset(ehAtomAddress
).atom
;
3697 new Reference
<x86_64
>(x86_64::kGroupSubordinate
, funcAtom
, ehAtom
);
3698 return (BaseAtom
*)funcAtom
;
3701 warning("can't find matching function for eh symbol %s", ehName
);
3705 template <typename A
>
3706 AtomAndOffset Reader
<A
>::findAtomAndOffsetForSection(pint_t addr
, unsigned int expectedSectionIndex
)
3708 AtomAndOffset ao
= findAtomAndOffset(addr
);
3709 if ( ao
.atom
!= NULL
) {
3710 if ( ((BaseAtom
*)(ao
.atom
))->getSectionIndex() == expectedSectionIndex
)
3713 // The atom found is not in the section expected.
3714 // This probably means there was a label at the end of the section.
3715 // Do a slow sequential lookup
3716 for (std::vector
<BaseAtom
*>::iterator it
=fAtoms
.begin(); it
!= fAtoms
.end(); ++it
) {
3717 BaseAtom
* atom
= *it
;
3718 if ( atom
->getSectionIndex() == expectedSectionIndex
) {
3719 pint_t objAddr
= atom
->getObjectAddress();
3720 if ( (objAddr
== addr
) || ((objAddr
< addr
) && (objAddr
+atom
->getSize() > addr
)) ) {
3721 return AtomAndOffset(atom
, addr
-atom
->getObjectAddress());
3725 // no atom found that matched section, fall back to one orginally found
3729 template <typename A
>
3730 AtomAndOffset Reader
<A
>::findAtomAndOffset(pint_t addr
)
3732 // STL has no built-in for "find largest key that is same or less than"
3733 typename
AddrToAtomMap::iterator it
= fAddrToAtom
.upper_bound(addr
);
3734 // if no atoms up to this address return none found
3735 if ( it
== fAddrToAtom
.begin() )
3736 return AtomAndOffset(NULL
);
3737 // otherwise upper_bound gets us next key, so we back up one
3739 AtomAndOffset result
;
3740 result
.atom
= it
->second
;
3741 result
.offset
= addr
- it
->first
;
3742 //fprintf(stderr, "findAtomAndOffset(0x%0llX) ==> %s (0x%0llX -> 0x%0llX)\n",
3743 // (uint64_t)addr, result.atom->getDisplayName(), (uint64_t)it->first, it->first+result.atom->getSize());
3747 // "scattered" relocations enable you to offset into an atom past the end of it
3748 // baseAddr is the address of the target atom,
3749 // realAddr is the points into it
3750 template <typename A
>
3751 AtomAndOffset Reader
<A
>::findAtomAndOffset(pint_t baseAddr
, pint_t realAddr
)
3753 typename
AddrToAtomMap::iterator it
= fAddrToAtom
.find(baseAddr
);
3754 if ( it
!= fAddrToAtom
.end() ) {
3755 AtomAndOffset result
;
3756 result
.atom
= it
->second
;
3757 result
.offset
= realAddr
- it
->first
;
3758 if ( result
.atom
->isThumb() )
3759 result
.offset
&= -2;
3760 //fprintf(stderr, "findAtomAndOffset(0x%08X, 0x%08X) => %s + 0x%08X\n", baseAddr, realAddr, result.atom->getDisplayName(), result.offset);
3763 // getting here means we have a scattered relocation to an address without a label
3764 // so, find the atom that contains the baseAddr, and offset from that to the readAddr
3765 AtomAndOffset result
= findAtomAndOffset(baseAddr
);
3766 result
.offset
+= (realAddr
-baseAddr
);
3771 /* Skip over a LEB128 value (signed or unsigned). */
3773 skip_leb128 (const uint8_t ** offset
, const uint8_t * end
)
3775 while (*offset
!= end
&& **offset
>= 0x80)
3781 /* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow
3782 or error. On overflow, skip past the rest of the uleb128. */
3784 read_uleb128 (const uint8_t ** offset
, const uint8_t * end
)
3786 uint64_t result
= 0;
3793 return (uint64_t) -1;
3795 b
= **offset
& 0x7f;
3797 if (bit
>= 64 || b
<< bit
>> bit
!= b
)
3798 result
= (uint64_t) -1;
3800 result
|= b
<< bit
, bit
+= 7;
3801 } while (*(*offset
)++ >= 0x80);
3806 /* Skip over a DWARF attribute of form FORM. */
3807 template <typename A
>
3808 bool Reader
<A
>::skip_form(const uint8_t ** offset
, const uint8_t * end
, uint64_t form
,
3809 uint8_t addr_size
, bool dwarf64
)
3819 case DW_FORM_block2
:
3820 if (end
- *offset
< 2)
3822 sz
= 2 + A::P::E::get16(*(uint16_t*)offset
);
3825 case DW_FORM_block4
:
3826 if (end
- *offset
< 4)
3828 sz
= 2 + A::P::E::get32(*(uint32_t*)offset
);
3846 case DW_FORM_string
:
3847 while (*offset
!= end
&& **offset
)
3856 sz
= read_uleb128 (offset
, end
);
3859 case DW_FORM_block1
:
3867 case DW_FORM_ref_udata
:
3868 skip_leb128 (offset
, end
);
3872 case DW_FORM_ref_addr
:
3879 if (end
- *offset
< sz
)
3885 template <typename A
>
3886 const char* Reader
<A
>::getDwarfString(uint64_t form
, const uint8_t* p
)
3888 if ( form
== DW_FORM_string
)
3889 return (const char*)p
;
3890 else if ( form
== DW_FORM_strp
) {
3891 uint32_t offset
= E::get32(*((uint32_t*)p
));
3892 const char* dwarfStrings
= (char*)(fHeader
) + fDwarfDebugStringSect
->offset();
3893 if ( offset
> fDwarfDebugStringSect
->size() ) {
3894 warning("unknown dwarf DW_FORM_strp (offset=0x%08X) is too big in %s\n", offset
, this->getPath());
3897 return &dwarfStrings
[offset
];
3899 warning("unknown dwarf string encoding (form=%lld) in %s\n", form
, this->getPath());
3904 // Look at the compilation unit DIE and determine
3905 // its NAME, compilation directory (in COMP_DIR) and its
3906 // line number information offset (in STMT_LIST). NAME and COMP_DIR
3907 // may be NULL (especially COMP_DIR) if they are not in the .o file;
3908 // STMT_LIST will be (uint64_t) -1.
3910 // At present this assumes that there's only one compilation unit DIE.
3912 template <typename A
>
3913 bool Reader
<A
>::read_comp_unit(const char ** name
, const char ** comp_dir
,
3914 uint64_t *stmt_list
)
3916 const uint8_t * debug_info
;
3917 const uint8_t * debug_abbrev
;
3920 const uint8_t * end
;
3921 const uint8_t * enda
;
3924 uint64_t abbrev_base
;
3926 uint8_t address_size
;
3931 *stmt_list
= (uint64_t) -1;
3933 if ( (fDwarfDebugInfoSect
== NULL
) || (fDwarfDebugAbbrevSect
== NULL
) )
3936 debug_info
= (uint8_t*)(fHeader
) + fDwarfDebugInfoSect
->offset();
3937 debug_abbrev
= (uint8_t*)(fHeader
) + fDwarfDebugAbbrevSect
->offset();
3940 if (fDwarfDebugInfoSect
->size() < 12)
3941 /* Too small to be a real debug_info section. */
3943 sz
= A::P::E::get32(*(uint32_t*)di
);
3945 dwarf64
= sz
== 0xffffffff;
3947 sz
= A::P::E::get64(*(uint64_t*)di
), di
+= 8;
3948 else if (sz
> 0xffffff00)
3949 /* Unknown dwarf format. */
3952 /* Verify claimed size. */
3953 if (sz
+ (di
- debug_info
) > fDwarfDebugInfoSect
->size() || sz
<= (dwarf64
? 23 : 11))
3956 vers
= A::P::E::get16(*(uint16_t*)di
);
3957 if (vers
< 2 || vers
> 3)
3958 /* DWARF version wrong for this code.
3959 Chances are we could continue anyway, but we don't know for sure. */
3963 /* Find the debug_abbrev section. */
3964 abbrev_base
= dwarf64
? A::P::E::get64(*(uint64_t*)di
) : A::P::E::get32(*(uint32_t*)di
);
3965 di
+= dwarf64
? 8 : 4;
3967 if (abbrev_base
> fDwarfDebugAbbrevSect
->size())
3969 da
= debug_abbrev
+ abbrev_base
;
3970 enda
= debug_abbrev
+ fDwarfDebugAbbrevSect
->size();
3972 address_size
= *di
++;
3974 /* Find the abbrev number we're looking for. */
3976 abbrev
= read_uleb128 (&di
, end
);
3977 if (abbrev
== (uint64_t) -1)
3980 /* Skip through the debug_abbrev section looking for that abbrev. */
3983 uint64_t this_abbrev
= read_uleb128 (&da
, enda
);
3986 if (this_abbrev
== abbrev
)
3987 /* This is almost always taken. */
3989 skip_leb128 (&da
, enda
); /* Skip the tag. */
3992 da
++; /* Skip the DW_CHILDREN_* value. */
3995 attr
= read_uleb128 (&da
, enda
);
3996 skip_leb128 (&da
, enda
);
3997 } while (attr
!= 0 && attr
!= (uint64_t) -1);
4002 /* Check that the abbrev is one for a DW_TAG_compile_unit. */
4003 if (read_uleb128 (&da
, enda
) != DW_TAG_compile_unit
)
4007 da
++; /* Skip the DW_CHILDREN_* value. */
4009 /* Now, go through the DIE looking for DW_AT_name,
4010 DW_AT_comp_dir, and DW_AT_stmt_list. */
4013 uint64_t attr
= read_uleb128 (&da
, enda
);
4014 uint64_t form
= read_uleb128 (&da
, enda
);
4016 if (attr
== (uint64_t) -1)
4021 if (form
== DW_FORM_indirect
)
4022 form
= read_uleb128 (&di
, end
);
4024 if (attr
== DW_AT_name
)
4025 *name
= getDwarfString(form
, di
);
4026 else if (attr
== DW_AT_comp_dir
)
4027 *comp_dir
= getDwarfString(form
, di
);
4028 else if (attr
== DW_AT_stmt_list
&& form
== DW_FORM_data4
)
4029 *stmt_list
= A::P::E::get32(*(uint32_t*)di
);
4030 else if (attr
== DW_AT_stmt_list
&& form
== DW_FORM_data8
)
4031 *stmt_list
= A::P::E::get64(*(uint64_t*)di
);
4032 if (! skip_form (&di
, end
, form
, address_size
, dwarf64
))
4037 template <typename A
>
4038 const char* Reader
<A
>::assureFullPath(const char* path
)
4040 if ( path
[0] == '/' )
4042 char cwdbuff
[MAXPATHLEN
];
4043 if ( getcwd(cwdbuff
, MAXPATHLEN
) != NULL
) {
4045 asprintf(&result
, "%s/%s", cwdbuff
, path
);
4046 if ( result
!= NULL
)
4055 // To implement architecture xxx, you must write template specializations for the following six methods:
4056 // Reader<xxx>::validFile()
4057 // Reader<xxx>::addRelocReference()
4058 // Reference<xxx>::getDescription()
4064 bool Reader
<ppc
>::validFile(const uint8_t* fileContent
, bool, cpu_subtype_t
)
4066 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
4067 if ( header
->magic() != MH_MAGIC
)
4069 if ( header
->cputype() != CPU_TYPE_POWERPC
)
4071 if ( header
->filetype() != MH_OBJECT
)
4077 bool Reader
<ppc64
>::validFile(const uint8_t* fileContent
, bool, cpu_subtype_t
)
4079 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
4080 if ( header
->magic() != MH_MAGIC_64
)
4082 if ( header
->cputype() != CPU_TYPE_POWERPC64
)
4084 if ( header
->filetype() != MH_OBJECT
)
4090 bool Reader
<x86
>::validFile(const uint8_t* fileContent
, bool, cpu_subtype_t
)
4092 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
4093 if ( header
->magic() != MH_MAGIC
)
4095 if ( header
->cputype() != CPU_TYPE_I386
)
4097 if ( header
->filetype() != MH_OBJECT
)
4103 bool Reader
<x86_64
>::validFile(const uint8_t* fileContent
, bool, cpu_subtype_t
)
4105 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
4106 if ( header
->magic() != MH_MAGIC_64
)
4108 if ( header
->cputype() != CPU_TYPE_X86_64
)
4110 if ( header
->filetype() != MH_OBJECT
)
4116 bool Reader
<arm
>::validFile(const uint8_t* fileContent
, bool subtypeMustMatch
, cpu_subtype_t subtype
)
4118 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
4119 if ( header
->magic() != MH_MAGIC
)
4121 if ( header
->cputype() != CPU_TYPE_ARM
)
4123 if ( header
->filetype() != MH_OBJECT
)
4125 if ( subtypeMustMatch
&& ((cpu_subtype_t
)header
->cpusubtype() != subtype
) )
4130 template <typename A
>
4131 bool Reader
<A
>::isWeakImportSymbol(const macho_nlist
<P
>* sym
)
4133 return ( ((sym
->n_type() & N_TYPE
) == N_UNDF
) && ((sym
->n_desc() & N_WEAK_REF
) != 0) );
4137 bool Reader
<ppc64
>::addRelocReference(const macho_section
<ppc64::P
>* sect
, const macho_relocation_info
<ppc64::P
>* reloc
)
4139 return addRelocReference_powerpc(sect
, reloc
);
4143 bool Reader
<ppc
>::addRelocReference(const macho_section
<ppc::P
>* sect
, const macho_relocation_info
<ppc::P
>* reloc
)
4145 return addRelocReference_powerpc(sect
, reloc
);
4150 // ppc and ppc64 both use the same relocations, so process them in one common routine
4152 template <typename A
>
4153 bool Reader
<A
>::addRelocReference_powerpc(const macho_section
<typename
A::P
>* sect
,
4154 const macho_relocation_info
<typename
A::P
>* reloc
)
4159 int32_t displacement
= 0;
4160 uint32_t instruction
= 0;
4161 uint32_t offsetInTarget
;
4163 bool result
= false;
4164 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
4165 const macho_relocation_info
<P
>* nextReloc
= &reloc
[1];
4166 const char* targetName
= NULL
;
4167 bool weakImport
= false;
4168 fixUpPtr
= (uint32_t*)((char*)(fHeader
) + sect
->offset() + reloc
->r_address());
4169 if ( reloc
->r_type() != PPC_RELOC_PAIR
)
4170 instruction
= BigEndian::get32(*fixUpPtr
);
4171 srcAddr
= sect
->addr() + reloc
->r_address();
4172 if ( reloc
->r_extern() ) {
4173 const macho_nlist
<P
>* targetSymbol
= &fSymbols
[reloc
->r_symbolnum()];
4174 targetName
= &fStrings
[targetSymbol
->n_strx()];
4175 weakImport
= this->isWeakImportSymbol(targetSymbol
);
4177 switch ( reloc
->r_type() ) {
4178 case PPC_RELOC_BR24
:
4180 if ( (instruction
& 0x4C000000) == 0x48000000 ) {
4181 displacement
= (instruction
& 0x03FFFFFC);
4182 if ( (displacement
& 0x02000000) != 0 )
4183 displacement
|= 0xFC000000;
4186 printf("bad instruction for BR24 reloc");
4188 if ( reloc
->r_extern() ) {
4189 offsetInTarget
= srcAddr
+ displacement
;
4190 if ( strncmp(targetName
, "___dtrace_probe$", 16) == 0 ) {
4191 makeByNameReference(A::kDtraceProbeSite
, srcAddr
, targetName
, 0);
4192 addDtraceExtraInfos(srcAddr
, &targetName
[16]);
4194 else if ( strncmp(targetName
, "___dtrace_isenabled$", 20) == 0 ) {
4195 makeByNameReference(A::kDtraceIsEnabledSite
, srcAddr
, targetName
, 0);
4196 addDtraceExtraInfos(srcAddr
, &targetName
[20]);
4198 else if ( weakImport
)
4199 makeByNameReference(A::kBranch24WeakImport
, srcAddr
, targetName
, offsetInTarget
);
4201 makeByNameReference(A::kBranch24
, srcAddr
, targetName
, offsetInTarget
);
4204 dstAddr
= srcAddr
+ displacement
;
4205 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
4206 ObjectFile::Atom
* atom
= findAtomAndOffset(dstAddr
).atom
;
4207 targetName
= atom
->getName();
4208 if ( (targetName
!= NULL
) && (strncmp(targetName
, "___dtrace_probe$", 16) == 0) ) {
4209 makeByNameReference(A::kDtraceProbeSite
, srcAddr
, targetName
, 0);
4210 addDtraceExtraInfos(srcAddr
, &targetName
[16]);
4212 else if ( (targetName
!= NULL
) && (strncmp(targetName
, "___dtrace_isenabled$", 20) == 0) ) {
4213 makeByNameReference(A::kDtraceIsEnabledSite
, srcAddr
, targetName
, 0);
4214 addDtraceExtraInfos(srcAddr
, &targetName
[20]);
4216 else if ( (atom
->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn
)
4217 && ((AnonymousAtom
<A
>*)atom
)->isWeakImportStub() )
4218 makeReference(A::kBranch24WeakImport
, srcAddr
, dstAddr
);
4220 makeReference(A::kBranch24
, srcAddr
, dstAddr
);
4224 case PPC_RELOC_BR14
:
4226 displacement
= (instruction
& 0x0000FFFC);
4227 if ( (displacement
& 0x00008000) != 0 )
4228 displacement
|= 0xFFFF0000;
4229 if ( reloc
->r_extern() ) {
4230 offsetInTarget
= srcAddr
+ displacement
;
4231 makeByNameReference(A::kBranch14
, srcAddr
, targetName
, offsetInTarget
);
4234 dstAddr
= srcAddr
+ displacement
;
4235 makeReference(A::kBranch14
, srcAddr
, dstAddr
);
4239 case PPC_RELOC_PAIR
:
4240 // skip, processed by a previous look ahead
4242 case PPC_RELOC_LO16
:
4244 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
4245 throw "PPC_RELOC_LO16 missing following pair";
4248 lowBits
= (instruction
& 0xFFFF);
4249 if ( reloc
->r_extern() ) {
4250 offsetInTarget
= (nextReloc
->r_address() << 16) | ((uint32_t)lowBits
& 0x0000FFFF);
4251 makeByNameReference(A::kAbsLow16
, srcAddr
, targetName
, offsetInTarget
);
4254 dstAddr
= (nextReloc
->r_address() << 16) + ((uint32_t)lowBits
& 0x0000FFFF);
4255 if ( reloc
->r_symbolnum() == R_ABS
) {
4256 // find absolute symbol that corresponds to pointerValue
4257 typename
AddrToAtomMap::iterator pos
= fAddrToAbsoluteAtom
.find(dstAddr
);
4258 if ( pos
!= fAddrToAbsoluteAtom
.end() )
4259 makeByNameReference(A::kAbsLow16
, srcAddr
, pos
->second
->getName(), 0);
4261 makeReference(A::kAbsLow16
, srcAddr
, dstAddr
);
4264 makeReference(A::kAbsLow16
, srcAddr
, dstAddr
);
4269 case PPC_RELOC_LO14
:
4271 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
4272 throw "PPC_RELOC_LO14 missing following pair";
4275 lowBits
= (instruction
& 0xFFFC);
4276 if ( reloc
->r_extern() ) {
4277 offsetInTarget
= (nextReloc
->r_address() << 16) | ((uint32_t)lowBits
& 0x0000FFFF);
4278 makeByNameReference(A::kAbsLow14
, srcAddr
, targetName
, offsetInTarget
);
4281 dstAddr
= (nextReloc
->r_address() << 16) | ((uint32_t)lowBits
& 0x0000FFFF);
4282 if ( reloc
->r_symbolnum() == R_ABS
) {
4283 // find absolute symbol that corresponds to pointerValue
4284 typename
AddrToAtomMap::iterator pos
= fAddrToAbsoluteAtom
.find(dstAddr
);
4285 if ( pos
!= fAddrToAbsoluteAtom
.end() )
4286 makeByNameReference(A::kAbsLow14
, srcAddr
, pos
->second
->getName(), 0);
4288 makeReference(A::kAbsLow14
, srcAddr
, dstAddr
);
4291 makeReference(A::kAbsLow14
, srcAddr
, dstAddr
);
4296 case PPC_RELOC_HI16
:
4298 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
4299 throw "PPC_RELOC_HI16 missing following pair";
4302 if ( reloc
->r_extern() ) {
4303 offsetInTarget
= ((instruction
& 0x0000FFFF) << 16) | (nextReloc
->r_address() & 0x0000FFFF);
4304 makeByNameReference(A::kAbsHigh16
, srcAddr
, targetName
, offsetInTarget
);
4307 dstAddr
= ((instruction
& 0x0000FFFF) << 16) | (nextReloc
->r_address() & 0x0000FFFF);
4308 if ( reloc
->r_symbolnum() == R_ABS
) {
4309 // find absolute symbol that corresponds to pointerValue
4310 typename
AddrToAtomMap::iterator pos
= fAddrToAbsoluteAtom
.find(dstAddr
);
4311 if ( pos
!= fAddrToAbsoluteAtom
.end() )
4312 makeByNameReference(A::kAbsHigh16
, srcAddr
, pos
->second
->getName(), 0);
4314 makeReference(A::kAbsHigh16
, srcAddr
, dstAddr
);
4317 makeReference(A::kAbsHigh16
, srcAddr
, dstAddr
);
4322 case PPC_RELOC_HA16
:
4324 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
4325 throw "PPC_RELOC_HA16 missing following pair";
4328 lowBits
= (nextReloc
->r_address() & 0x0000FFFF);
4329 if ( reloc
->r_extern() ) {
4330 offsetInTarget
= ((instruction
& 0x0000FFFF) << 16) + (int32_t)lowBits
;
4331 makeByNameReference(A::kAbsHigh16AddLow
, srcAddr
, targetName
, offsetInTarget
);
4334 dstAddr
= ((instruction
& 0x0000FFFF) << 16) + (int32_t)lowBits
;
4335 if ( reloc
->r_symbolnum() == R_ABS
) {
4336 // find absolute symbol that corresponds to pointerValue
4337 typename
AddrToAtomMap::iterator pos
= fAddrToAbsoluteAtom
.find(dstAddr
);
4338 if ( pos
!= fAddrToAbsoluteAtom
.end() )
4339 makeByNameReference(A::kAbsHigh16AddLow
, srcAddr
, pos
->second
->getName(), 0);
4341 makeReference(A::kAbsHigh16AddLow
, srcAddr
, dstAddr
);
4344 makeReference(A::kAbsHigh16AddLow
, srcAddr
, dstAddr
);
4349 case PPC_RELOC_VANILLA
:
4351 pint_t pointerValue
= P::getP(*((pint_t
*)fixUpPtr
));
4352 if ( reloc
->r_extern() ) {
4354 makeByNameReference(A::kPointerWeakImport
, srcAddr
, targetName
, pointerValue
);
4356 makeByNameReference(A::kPointer
, srcAddr
, targetName
, pointerValue
);
4359 new Reference
<A
>(A::kPointer
, findAtomAndOffset(srcAddr
), findAtomAndOffsetForSection(pointerValue
, reloc
->r_symbolnum()));
4363 case PPC_RELOC_JBSR
:
4364 // this is from -mlong-branch codegen. We ignore the jump island and make reference to the real target
4365 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
4366 throw "PPC_RELOC_JBSR missing following pair";
4368 if ( !fHasLongBranchStubs
)
4369 warning("object file compiled with -mlong-branch which is no longer needed. To remove this warning, recompile without -mlong-branch: %s", fPath
);
4370 fHasLongBranchStubs
= true;
4372 if ( reloc
->r_extern() ) {
4373 throw "PPC_RELOC_JBSR should not be using an external relocation";
4375 makeReference(A::kBranch24
, srcAddr
, nextReloc
->r_address());
4376 if ( (instruction
& 0x4C000000) == 0x48000000 ) {
4377 displacement
= (instruction
& 0x03FFFFFC);
4378 if ( (displacement
& 0x02000000) != 0 )
4379 displacement
|= 0xFC000000;
4382 fprintf(stderr
, "bad instruction for BR24 reloc");
4386 warning("unknown relocation type %d", reloc
->r_type());
4390 const macho_scattered_relocation_info
<P
>* sreloc
= (macho_scattered_relocation_info
<P
>*)reloc
;
4391 srcAddr
= sect
->addr() + sreloc
->r_address();
4392 dstAddr
= sreloc
->r_value();
4393 uint32_t betterDstAddr
;
4394 fixUpPtr
= (uint32_t*)((char*)(fHeader
) + sect
->offset() + sreloc
->r_address());
4395 const macho_scattered_relocation_info
<P
>* nextSReloc
= &sreloc
[1];
4396 const macho_relocation_info
<P
>* nextReloc
= &reloc
[1];
4397 // file format allows pair to be scattered or not
4398 bool nextRelocIsPair
= false;
4399 uint32_t nextRelocAddress
= 0;
4400 uint32_t nextRelocValue
= 0;
4401 if ( (nextReloc
->r_address() & R_SCATTERED
) == 0 ) {
4402 if ( nextReloc
->r_type() == PPC_RELOC_PAIR
) {
4403 nextRelocIsPair
= true;
4404 nextRelocAddress
= nextReloc
->r_address();
4409 if ( nextSReloc
->r_type() == PPC_RELOC_PAIR
) {
4410 nextRelocIsPair
= true;
4411 nextRelocAddress
= nextSReloc
->r_address();
4412 nextRelocValue
= nextSReloc
->r_value();
4416 switch (sreloc
->r_type()) {
4417 case PPC_RELOC_VANILLA
:
4419 betterDstAddr
= P::getP(*(pint_t
*)fixUpPtr
);
4420 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
4421 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
4422 makeReferenceWithToBase(A::kPointer
, srcAddr
, betterDstAddr
, dstAddr
);
4425 case PPC_RELOC_BR14
:
4427 instruction
= BigEndian::get32(*fixUpPtr
);
4428 displacement
= (instruction
& 0x0000FFFC);
4429 if ( (displacement
& 0x00008000) != 0 )
4430 displacement
|= 0xFFFF0000;
4431 betterDstAddr
= srcAddr
+displacement
;
4432 //fprintf(stderr, "betterDstAddr=0x%08X, srcAddr=0x%08X, displacement=0x%08X\n", betterDstAddr, srcAddr, displacement);
4433 makeReferenceWithToBase(A::kBranch14
, srcAddr
, betterDstAddr
, dstAddr
);
4436 case PPC_RELOC_BR24
:
4438 instruction
= BigEndian::get32(*fixUpPtr
);
4439 if ( (instruction
& 0x4C000000) == 0x48000000 ) {
4440 displacement
= (instruction
& 0x03FFFFFC);
4441 if ( (displacement
& 0x02000000) != 0 )
4442 displacement
|= 0xFC000000;
4443 betterDstAddr
= srcAddr
+displacement
;
4444 makeReferenceWithToBase(A::kBranch24
, srcAddr
, betterDstAddr
, dstAddr
);
4448 case PPC_RELOC_LO16_SECTDIFF
:
4450 if ( ! nextRelocIsPair
) {
4451 throw "PPC_RELOC_LO16_SECTDIFF missing following pair";
4453 instruction
= BigEndian::get32(*fixUpPtr
);
4454 lowBits
= (instruction
& 0xFFFF);
4455 displacement
= (nextRelocAddress
<< 16) | ((uint32_t)lowBits
& 0x0000FFFF);
4456 makeReferenceWithToBase(A::kPICBaseLow16
, srcAddr
, nextRelocValue
, nextRelocValue
+ displacement
, dstAddr
);
4459 case PPC_RELOC_LO14_SECTDIFF
:
4461 if ( ! nextRelocIsPair
) {
4462 throw "PPC_RELOC_LO14_SECTDIFF missing following pair";
4464 instruction
= BigEndian::get32(*fixUpPtr
);
4465 lowBits
= (instruction
& 0xFFFC);
4466 displacement
= (nextRelocAddress
<< 16) | ((uint32_t)lowBits
& 0x0000FFFF);
4467 makeReferenceWithToBase(A::kPICBaseLow14
, srcAddr
, nextRelocValue
, nextRelocValue
+ displacement
, dstAddr
);
4470 case PPC_RELOC_HA16_SECTDIFF
:
4472 if ( ! nextRelocIsPair
) {
4473 throw "PPC_RELOC_HA16_SECTDIFF missing following pair";
4475 instruction
= BigEndian::get32(*fixUpPtr
);
4476 lowBits
= (nextRelocAddress
& 0x0000FFFF);
4477 displacement
= ((instruction
& 0x0000FFFF) << 16) + (int32_t)lowBits
;
4478 makeReferenceWithToBase(A::kPICBaseHigh16
, srcAddr
, nextRelocValue
, nextRelocValue
+ displacement
, dstAddr
);
4481 case PPC_RELOC_LO14
:
4483 if ( ! nextRelocIsPair
) {
4484 throw "PPC_RELOC_LO14 missing following pair";
4486 instruction
= BigEndian::get32(*fixUpPtr
);
4487 lowBits
= (instruction
& 0xFFFC);
4488 betterDstAddr
= (nextRelocAddress
<< 16) + ((uint32_t)lowBits
& 0x0000FFFF);
4489 makeReferenceWithToBase(A::kAbsLow14
, srcAddr
, betterDstAddr
, dstAddr
);
4492 case PPC_RELOC_LO16
:
4494 if ( ! nextRelocIsPair
) {
4495 throw "PPC_RELOC_LO16 missing following pair";
4497 instruction
= BigEndian::get32(*fixUpPtr
);
4498 lowBits
= (instruction
& 0xFFFF);
4499 betterDstAddr
= (nextRelocAddress
<< 16) + ((uint32_t)lowBits
& 0x0000FFFF);
4500 makeReferenceWithToBase(A::kAbsLow16
, srcAddr
, betterDstAddr
, dstAddr
);
4503 case PPC_RELOC_HA16
:
4505 if ( ! nextRelocIsPair
) {
4506 throw "PPC_RELOC_HA16 missing following pair";
4508 instruction
= BigEndian::get32(*fixUpPtr
);
4509 lowBits
= (nextRelocAddress
& 0xFFFF);
4510 betterDstAddr
= ((instruction
& 0xFFFF) << 16) + (int32_t)lowBits
;
4511 makeReferenceWithToBase(A::kAbsHigh16AddLow
, srcAddr
, betterDstAddr
, dstAddr
);
4514 case PPC_RELOC_HI16
:
4516 if ( ! nextRelocIsPair
) {
4517 throw "PPC_RELOC_HI16 missing following pair";
4519 instruction
= BigEndian::get32(*fixUpPtr
);
4520 lowBits
= (nextRelocAddress
& 0xFFFF);
4521 betterDstAddr
= ((instruction
& 0xFFFF) << 16) | (lowBits
& 0x0000FFFF);
4522 makeReferenceWithToBase(A::kAbsHigh16
, srcAddr
, betterDstAddr
, dstAddr
);
4525 case PPC_RELOC_SECTDIFF
:
4526 case PPC_RELOC_LOCAL_SECTDIFF
:
4528 if ( ! nextRelocIsPair
) {
4529 throw "PPC_RELOC_SECTDIFF missing following pair";
4531 Kinds kind
= A::kPointerDiff32
;;
4532 uint32_t contentAddr
= 0;
4533 switch ( sreloc
->r_length() ) {
4535 throw "bad diff relocations r_length (0) for ppc architecture";
4537 kind
= A::kPointerDiff16
;
4538 contentAddr
= BigEndian::get16(*((uint16_t*)fixUpPtr
));
4541 kind
= A::kPointerDiff32
;
4542 contentAddr
= BigEndian::get32(*fixUpPtr
);
4545 kind
= A::kPointerDiff64
;
4546 contentAddr
= BigEndian::get64(*((uint64_t*)fixUpPtr
));
4549 AtomAndOffset srcao
= findAtomAndOffset(srcAddr
);
4550 AtomAndOffset fromao
= findAtomAndOffset(nextRelocValue
);
4551 AtomAndOffset toao
= findAtomAndOffset(dstAddr
);
4552 // check for addend encoded in the section content
4553 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
4554 // dstAddr, nextRelocValue, contentAddr);
4555 if ( (dstAddr
- nextRelocValue
) != contentAddr
) {
4556 if ( toao
.atom
== srcao
.atom
)
4557 toao
.offset
+= (contentAddr
+ nextRelocValue
) - dstAddr
;
4558 else if ( fromao
.atom
== srcao
.atom
)
4559 toao
.offset
+= (contentAddr
+ nextRelocValue
) - dstAddr
;
4561 fromao
.offset
+= (dstAddr
- contentAddr
) - nextRelocValue
;
4563 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
4564 // srcao.atom->getDisplayName(), srcao.offset,
4565 // fromao.atom->getDisplayName(), fromao.offset,
4566 // toao.atom->getDisplayName(), toao.offset);
4567 new Reference
<A
>(kind
, srcao
, fromao
, toao
);
4570 case PPC_RELOC_PAIR
:
4572 case PPC_RELOC_HI16_SECTDIFF
:
4573 warning("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF");
4576 warning("unknown scattered relocation type %d", sreloc
->r_type());
4584 bool Reader
<x86
>::addRelocReference(const macho_section
<x86::P
>* sect
, const macho_relocation_info
<x86::P
>* reloc
)
4589 bool result
= false;
4590 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
4591 srcAddr
= sect
->addr() + reloc
->r_address();
4592 fixUpPtr
= (uint32_t*)((char*)(fHeader
) + sect
->offset() + reloc
->r_address());
4593 switch ( reloc
->r_type() ) {
4594 case GENERIC_RELOC_VANILLA
:
4596 x86::ReferenceKinds kind
= x86::kPointer
;
4597 uint32_t pointerValue
= E::get32(*fixUpPtr
);
4598 if ( reloc
->r_pcrel() ) {
4599 switch( reloc
->r_length() ) {
4601 kind
= x86::kPCRel8
;
4602 pointerValue
= srcAddr
+ *((int8_t*)fixUpPtr
) + sizeof(int8_t);
4605 kind
= x86::kPCRel16
;
4606 pointerValue
= srcAddr
+ (int16_t)E::get16(*((uint16_t*)fixUpPtr
)) + sizeof(uint16_t);
4609 kind
= x86::kPCRel32
;
4610 pointerValue
+= srcAddr
+ sizeof(uint32_t);
4613 throw "bad pc-rel vanilla relocation length";
4616 else if ( strcmp(sect
->segname(), "__TEXT") == 0 ) {
4617 kind
= x86::kAbsolute32
;
4618 if ( reloc
->r_length() != 2 )
4619 throw "bad vanilla relocation length";
4622 kind
= x86::kPointer
;
4623 if ( reloc
->r_length() != 2 )
4624 throw "bad vanilla relocation length";
4626 if ( reloc
->r_extern() ) {
4627 const macho_nlist
<P
>* targetSymbol
= &fSymbols
[reloc
->r_symbolnum()];
4628 if ( this->isWeakImportSymbol(targetSymbol
) ) {
4629 if ( reloc
->r_pcrel() )
4630 kind
= x86::kPCRel32WeakImport
;
4632 kind
= x86::kPointerWeakImport
;
4634 const char* targetName
= &fStrings
[targetSymbol
->n_strx()];
4635 if ( strncmp(targetName
, "___dtrace_probe$", 16) == 0 ) {
4636 makeByNameReference(x86::kDtraceProbeSite
, srcAddr
, targetName
, 0);
4637 addDtraceExtraInfos(srcAddr
, &targetName
[16]);
4639 else if ( strncmp(targetName
, "___dtrace_isenabled$", 20) == 0 ) {
4640 makeByNameReference(x86::kDtraceIsEnabledSite
, srcAddr
, targetName
, 0);
4641 addDtraceExtraInfos(srcAddr
, &targetName
[20]);
4644 makeByNameReference(kind
, srcAddr
, targetName
, pointerValue
);
4647 AtomAndOffset targetAO
= findAtomAndOffsetForSection(pointerValue
, reloc
->r_symbolnum());
4648 const char* targetName
= targetAO
.atom
->getName();
4649 if ( (targetName
!= NULL
) && (strncmp(targetName
, "___dtrace_probe$", 16) == 0) ) {
4650 makeByNameReference(x86::kDtraceProbeSite
, srcAddr
, targetName
, 0);
4651 addDtraceExtraInfos(srcAddr
, &targetName
[16]);
4653 else if ( (targetName
!= NULL
) && (strncmp(targetName
, "___dtrace_isenabled$", 20) == 0) ) {
4654 makeByNameReference(x86::kDtraceIsEnabledSite
, srcAddr
, targetName
, 0);
4655 addDtraceExtraInfos(srcAddr
, &targetName
[20]);
4657 // if this is a reference to a stub, we need to see if the stub is for a weak imported symbol
4658 else if ( reloc
->r_pcrel() && (targetAO
.atom
->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn
)
4659 && ((AnonymousAtom
<x86
>*)targetAO
.atom
)->isWeakImportStub() )
4660 new Reference
<x86
>(x86::kPCRel32WeakImport
, findAtomAndOffset(srcAddr
), targetAO
);
4661 else if ( reloc
->r_symbolnum() != R_ABS
)
4662 new Reference
<x86
>(kind
, findAtomAndOffset(srcAddr
), targetAO
);
4664 // find absolute symbol that corresponds to pointerValue
4665 AddrToAtomMap::iterator pos
= fAddrToAbsoluteAtom
.find(pointerValue
);
4666 if ( pos
!= fAddrToAbsoluteAtom
.end() )
4667 makeByNameReference(kind
, srcAddr
, pos
->second
->getName(), 0);
4669 throwf("R_ABS reloc but no absolute symbol at target address");
4675 warning("unknown relocation type %d", reloc
->r_type());
4679 const macho_scattered_relocation_info
<P
>* sreloc
= (macho_scattered_relocation_info
<P
>*)reloc
;
4680 srcAddr
= sect
->addr() + sreloc
->r_address();
4681 dstAddr
= sreloc
->r_value();
4682 fixUpPtr
= (uint32_t*)((char*)(fHeader
) + sect
->offset() + sreloc
->r_address());
4683 const macho_scattered_relocation_info
<P
>* nextSReloc
= &sreloc
[1];
4684 const macho_relocation_info
<P
>* nextReloc
= &reloc
[1];
4685 pint_t betterDstAddr
;
4686 // file format allows pair to be scattered or not
4687 bool nextRelocIsPair
= false;
4688 uint32_t nextRelocAddress
= 0;
4689 uint32_t nextRelocValue
= 0;
4690 if ( (nextReloc
->r_address() & R_SCATTERED
) == 0 ) {
4691 if ( nextReloc
->r_type() == GENERIC_RELOC_PAIR
) {
4692 nextRelocIsPair
= true;
4693 nextRelocAddress
= nextReloc
->r_address();
4698 if ( nextSReloc
->r_type() == GENERIC_RELOC_PAIR
) {
4699 nextRelocIsPair
= true;
4700 nextRelocAddress
= nextSReloc
->r_address();
4701 nextRelocValue
= nextSReloc
->r_value();
4704 switch (sreloc
->r_type()) {
4705 case GENERIC_RELOC_VANILLA
:
4706 betterDstAddr
= LittleEndian::get32(*fixUpPtr
);
4707 //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr);
4708 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
4709 if ( sreloc
->r_pcrel() ) {
4710 switch ( sreloc
->r_length() ) {
4712 betterDstAddr
+= srcAddr
+ 4;
4713 makeReferenceWithToBase(x86::kPCRel32
, srcAddr
, betterDstAddr
, dstAddr
);
4716 betterDstAddr
= LittleEndian::get16(*((uint16_t*)fixUpPtr
)) + srcAddr
+ 2;
4717 makeReferenceWithToBase(x86::kPCRel16
, srcAddr
, betterDstAddr
, dstAddr
);
4720 betterDstAddr
= *((uint8_t*)fixUpPtr
) + srcAddr
+ 1;
4721 makeReferenceWithToBase(x86::kPCRel8
, srcAddr
, betterDstAddr
, dstAddr
);
4724 throwf("unsupported r_length=3 for scattered pc-rel vanilla reloc");
4729 if ( sreloc
->r_length() != 2 )
4730 throwf("unsupported r_length=%d for scattered vanilla reloc", sreloc
->r_length());
4731 if ( strcmp(sect
->segname(), "__TEXT") == 0 )
4732 makeReferenceWithToBase(x86::kAbsolute32
, srcAddr
, betterDstAddr
, dstAddr
);
4734 makeReferenceWithToBase(x86::kPointer
, srcAddr
, betterDstAddr
, dstAddr
);
4737 case GENERIC_RELOC_SECTDIFF
:
4738 case GENERIC_RELOC_LOCAL_SECTDIFF
:
4740 if ( !nextRelocIsPair
) {
4741 throw "GENERIC_RELOC_SECTDIFF missing following pair";
4743 x86::ReferenceKinds kind
= x86::kPointerDiff
;
4744 uint32_t contentAddr
= 0;
4745 switch ( sreloc
->r_length() ) {
4748 throw "bad length for GENERIC_RELOC_SECTDIFF";
4750 kind
= x86::kPointerDiff16
;
4751 contentAddr
= LittleEndian::get16(*((uint16_t*)fixUpPtr
));
4754 kind
= x86::kPointerDiff
;
4755 contentAddr
= LittleEndian::get32(*fixUpPtr
);
4758 AtomAndOffset srcao
= findAtomAndOffset(srcAddr
);
4759 AtomAndOffset fromao
= findAtomAndOffset(nextRelocValue
);
4760 AtomAndOffset toao
= findAtomAndOffset(dstAddr
);
4761 // check for addend encoded in the section content
4762 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
4763 // dstAddr, nextRelocValue, contentAddr);
4764 if ( (dstAddr
- nextRelocValue
) != contentAddr
) {
4765 if ( toao
.atom
== srcao
.atom
)
4766 toao
.offset
+= (contentAddr
+ nextRelocValue
) - dstAddr
;
4767 else if ( fromao
.atom
== srcao
.atom
)
4768 toao
.offset
+= (contentAddr
+ nextRelocValue
) - dstAddr
;
4770 fromao
.offset
+= (dstAddr
- contentAddr
) - nextRelocValue
;
4772 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
4773 // srcao.atom->getDisplayName(), srcao.offset,
4774 // fromao.atom->getDisplayName(), fromao.offset,
4775 // toao.atom->getDisplayName(), toao.offset);
4776 new Reference
<x86
>(kind
, srcao
, fromao
, toao
);
4779 case GENERIC_RELOC_PAIR
:
4780 // do nothing, already used via a look ahead
4783 warning("unknown scattered relocation type %d", sreloc
->r_type());
4790 bool Reader
<x86_64
>::addRelocReference(const macho_section
<x86_64::P
>* sect
, const macho_relocation_info
<x86_64::P
>* reloc
)
4793 uint64_t dstAddr
= 0;
4796 x86_64::ReferenceKinds kind
= x86_64::kNoFixUp
;
4797 bool result
= false;
4798 const macho_nlist
<P
>* targetSymbol
= NULL
;
4799 const char* targetName
= NULL
;
4800 srcAddr
= sect
->addr() + reloc
->r_address();
4801 fixUpPtr
= (uint32_t*)((char*)(fHeader
) + sect
->offset() + reloc
->r_address());
4802 //fprintf(stderr, "addReloc type=%d, len=%d, address=0x%X\n", reloc->r_type(), reloc->r_length(), reloc->r_address());
4803 if ( reloc
->r_extern() ) {
4804 targetSymbol
= &fSymbols
[reloc
->r_symbolnum()];
4805 targetName
= &fStrings
[targetSymbol
->n_strx()];
4807 switch ( reloc
->r_type() ) {
4808 case X86_64_RELOC_UNSIGNED
:
4809 if ( reloc
->r_pcrel() )
4810 throw "pcrel and X86_64_RELOC_UNSIGNED not supported";
4811 switch ( reloc
->r_length() ) {
4814 throw "length < 2 and X86_64_RELOC_UNSIGNED not supported";
4816 kind
= x86_64::kPointer32
;
4819 if ( reloc
->r_extern() && isWeakImportSymbol(targetSymbol
) )
4820 kind
= x86_64::kPointerWeakImport
;
4822 kind
= x86_64::kPointer
;
4825 dstAddr
= E::get64(*((uint64_t*)fixUpPtr
));
4826 if ( reloc
->r_extern() ) {
4827 makeReferenceToSymbol(kind
, srcAddr
, targetSymbol
, dstAddr
);
4830 makeReference(kind
, srcAddr
, dstAddr
);
4831 // verify that dstAddr is in the section being targeted
4832 int sectNum
= reloc
->r_symbolnum();
4833 const macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)fSegment
+ sizeof(macho_segment_command
<P
>));
4834 const macho_section
<P
>* const targetSection
= §ionsStart
[sectNum
-1];
4835 if ( (dstAddr
< targetSection
->addr()) || (dstAddr
> (targetSection
->addr()+targetSection
->size())) ) {
4836 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
4837 srcAddr
, sect
->sectname(), targetSection
->sectname());
4841 case X86_64_RELOC_SIGNED
:
4842 case X86_64_RELOC_SIGNED_1
:
4843 case X86_64_RELOC_SIGNED_2
:
4844 case X86_64_RELOC_SIGNED_4
:
4845 if ( ! reloc
->r_pcrel() )
4846 throw "not pcrel and X86_64_RELOC_SIGNED* not supported";
4847 if ( reloc
->r_length() != 2 )
4848 throw "length != 2 and X86_64_RELOC_SIGNED* not supported";
4849 addend
= (int64_t)((int32_t)(E::get32(*fixUpPtr
)));
4850 if ( reloc
->r_extern() ) {
4851 switch ( reloc
->r_type() ) {
4852 case X86_64_RELOC_SIGNED
:
4853 kind
= x86_64::kPCRel32
;
4854 // begin support for old .o files before X86_64_RELOC_SIGNED_1 was created
4855 if ( addend
== (uint64_t)(-1) ) {
4857 kind
= x86_64::kPCRel32_1
;
4859 else if ( addend
== (uint64_t)(-2) ) {
4861 kind
= x86_64::kPCRel32_2
;
4863 else if ( addend
== (uint64_t)(-4) ) {
4865 kind
= x86_64::kPCRel32_4
;
4868 // end support for old .o files before X86_64_RELOC_SIGNED_1 was created
4869 case X86_64_RELOC_SIGNED_1
:
4870 kind
= x86_64::kPCRel32_1
;
4873 case X86_64_RELOC_SIGNED_2
:
4874 kind
= x86_64::kPCRel32_2
;
4877 case X86_64_RELOC_SIGNED_4
:
4878 kind
= x86_64::kPCRel32_4
;
4882 makeReferenceToSymbol(kind
, srcAddr
, targetSymbol
, addend
);
4885 uint64_t ripRelativeOffset
= addend
;
4886 switch ( reloc
->r_type() ) {
4887 case X86_64_RELOC_SIGNED
:
4888 dstAddr
= srcAddr
+ 4 + ripRelativeOffset
;
4889 kind
= x86_64::kPCRel32
;
4891 case X86_64_RELOC_SIGNED_1
:
4892 dstAddr
= srcAddr
+ 5 + ripRelativeOffset
;
4893 kind
= x86_64::kPCRel32_1
;
4895 case X86_64_RELOC_SIGNED_2
:
4896 dstAddr
= srcAddr
+ 6 + ripRelativeOffset
;
4897 kind
= x86_64::kPCRel32_2
;
4899 case X86_64_RELOC_SIGNED_4
:
4900 dstAddr
= srcAddr
+ 8 + ripRelativeOffset
;
4901 kind
= x86_64::kPCRel32_4
;
4904 makeReference(kind
, srcAddr
, dstAddr
);
4905 // verify that dstAddr is in the section being targeted
4906 int sectNum
= reloc
->r_symbolnum();
4907 const macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)fSegment
+ sizeof(macho_segment_command
<P
>));
4908 const macho_section
<P
>* const targetSection
= §ionsStart
[sectNum
-1];
4909 if ( (dstAddr
< targetSection
->addr()) || (dstAddr
> (targetSection
->addr()+targetSection
->size())) ) {
4910 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
4911 srcAddr
, sect
->sectname(), targetSection
->sectname());
4915 case X86_64_RELOC_BRANCH
:
4916 if ( ! reloc
->r_pcrel() )
4917 throw "not pcrel and X86_64_RELOC_BRANCH not supported";
4918 if ( reloc
->r_length() == 2 ) {
4919 dstAddr
= (int64_t)((int32_t)(E::get32(*fixUpPtr
)));
4920 if ( reloc
->r_extern() ) {
4921 if ( strncmp(targetName
, "___dtrace_probe$", 16) == 0 ) {
4922 makeByNameReference(x86_64::kDtraceProbeSite
, srcAddr
, targetName
, 0);
4923 addDtraceExtraInfos(srcAddr
, &targetName
[16]);
4925 else if ( strncmp(targetName
, "___dtrace_isenabled$", 20) == 0 ) {
4926 makeByNameReference(x86_64::kDtraceIsEnabledSite
, srcAddr
, targetName
, 0);
4927 addDtraceExtraInfos(srcAddr
, &targetName
[16]);
4929 else if ( isWeakImportSymbol(targetSymbol
) )
4930 makeReferenceToSymbol(x86_64::kBranchPCRel32WeakImport
, srcAddr
, targetSymbol
, dstAddr
);
4932 makeReferenceToSymbol(x86_64::kBranchPCRel32
, srcAddr
, targetSymbol
, dstAddr
);
4935 makeReference(x86_64::kBranchPCRel32
, srcAddr
, srcAddr
+4+dstAddr
);
4938 else if ( reloc
->r_length() == 0 ) {
4939 dstAddr
= *((int8_t*)fixUpPtr
);
4940 if ( reloc
->r_extern() ) {
4941 makeReferenceToSymbol(x86_64::kBranchPCRel8
, srcAddr
, targetSymbol
, dstAddr
);
4944 makeReference(x86_64::kBranchPCRel8
, srcAddr
, srcAddr
+1+dstAddr
);
4948 throwf("length=%d and X86_64_RELOC_BRANCH not supported", reloc
->r_length());;
4951 case X86_64_RELOC_GOT
:
4952 if ( ! reloc
->r_extern() )
4953 throw "not extern and X86_64_RELOC_GOT not supported";
4954 if ( ! reloc
->r_pcrel() )
4955 throw "not pcrel and X86_64_RELOC_GOT not supported";
4956 if ( reloc
->r_length() != 2 )
4957 throw "length != 2 and X86_64_RELOC_GOT not supported";
4958 addend
= (int64_t)((int32_t)(E::get32(*fixUpPtr
)));
4959 if ( isWeakImportSymbol(targetSymbol
) )
4960 makeReferenceToSymbol(x86_64::kPCRel32GOTWeakImport
, srcAddr
, targetSymbol
, addend
);
4962 makeReferenceToSymbol(x86_64::kPCRel32GOT
, srcAddr
, targetSymbol
, addend
);
4964 case X86_64_RELOC_GOT_LOAD
:
4965 if ( ! reloc
->r_extern() )
4966 throw "not extern and X86_64_RELOC_GOT_LOAD not supported";
4967 if ( ! reloc
->r_pcrel() )
4968 throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported";
4969 if ( reloc
->r_length() != 2 )
4970 throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported";
4971 addend
= (int64_t)((int32_t)(E::get32(*fixUpPtr
)));
4972 if ( isWeakImportSymbol(targetSymbol
) )
4973 makeReferenceToSymbol(x86_64::kPCRel32GOTLoadWeakImport
, srcAddr
, targetSymbol
, addend
);
4975 makeReferenceToSymbol(x86_64::kPCRel32GOTLoad
, srcAddr
, targetSymbol
, addend
);
4977 case X86_64_RELOC_SUBTRACTOR
:
4979 if ( reloc
->r_pcrel() )
4980 throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
4981 if ( reloc
->r_length() < 2 )
4982 throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
4983 if ( !reloc
->r_extern() )
4984 throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1";
4985 const macho_relocation_info
<x86_64::P
>* nextReloc
= &reloc
[1];
4986 if ( nextReloc
->r_type() != X86_64_RELOC_UNSIGNED
)
4987 throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED";
4989 if ( nextReloc
->r_pcrel() )
4990 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
4991 if ( nextReloc
->r_length() != reloc
->r_length() )
4992 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length";
4993 Reference
<x86_64
>* ref
;
4994 bool negativeAddend
;
4995 if ( reloc
->r_length() == 2 ) {
4996 kind
= x86_64::kPointerDiff32
;
4997 dstAddr
= E::get32(*fixUpPtr
); // addend is in content
4998 negativeAddend
= ((dstAddr
& 0x80000000) != 0);
5001 kind
= x86_64::kPointerDiff
;
5002 dstAddr
= E::get64(*((uint64_t*)fixUpPtr
)); // addend is in content
5003 negativeAddend
= ((dstAddr
& 0x8000000000000000ULL
) != 0);
5005 AtomAndOffset inAtomAndOffset
= this->findAtomAndOffset(srcAddr
);
5006 ObjectFile::Atom
* inAtom
= inAtomAndOffset
.atom
;
5007 // create reference with "to" target
5008 if ( nextReloc
->r_extern() ) {
5009 const macho_nlist
<P
>* targetSymbol
= &fSymbols
[nextReloc
->r_symbolnum()];
5010 const char* targetName
= &fStrings
[targetSymbol
->n_strx()];
5011 ref
= makeReferenceToSymbol(kind
, srcAddr
, targetSymbol
, 0);
5012 // if "to" is in this atom, change by-name to a direct reference
5013 if ( strcmp(targetName
, inAtom
->getName()) == 0 )
5014 ref
->setTarget(*inAtom
, 0);
5017 ref
= makeReference(kind
, srcAddr
, dstAddr
);
5019 // add in "from" target
5020 if ( reloc
->r_extern() ) {
5021 const macho_nlist
<P
>* targetFromSymbol
= &fSymbols
[reloc
->r_symbolnum()];
5022 const char* fromTargetName
= &fStrings
[targetFromSymbol
->n_strx()];
5023 if ( (targetFromSymbol
->n_type() & N_EXT
) == 0 ) {
5024 // from target is translation unit scoped, so use a direct reference
5025 ref
->setFromTarget(*(findAtomAndOffset(targetSymbol
->n_value()).atom
));
5027 else if ( strcmp(fromTargetName
, inAtom
->getName()) == 0 ) {
5028 // if "from" is in this atom, change by-name to a direct reference
5029 ref
->setFromTarget(*inAtom
);
5032 // some non-static other atom
5033 ref
->setFromTargetName(fromTargetName
);
5037 throw "X86_64_RELOC_SUBTRACTOR not supported with r_extern=0";
5039 // addend goes in from side iff negative
5040 if ( negativeAddend
)
5041 ref
->setFromTargetOffset(-dstAddr
);
5043 ref
->setToTargetOffset(dstAddr
);
5047 warning("unknown relocation type %d", reloc
->r_type());
5053 /// Reader<arm>::addRelocReference -
5054 /// turns arm relocation entries into references. Returns true if the next
5055 /// relocation should be skipped, false otherwise.
5057 bool Reader
<arm
>::addRelocReference(const macho_section
<arm::P
>* sect
,
5058 const macho_relocation_info
<arm::P
>* reloc
)
5060 uint32_t * fixUpPtr
;
5061 int32_t displacement
;
5062 uint32_t instruction
= 0;
5063 bool result
= false;
5066 uint32_t pointerValue
;
5067 arm::ReferenceKinds kind
= arm::kNoFixUp
;
5069 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
5070 // non-scattered relocation
5071 const char* targetName
= NULL
;
5072 bool weakImport
= false;
5074 srcAddr
= sect
->addr() + reloc
->r_address();
5075 fixUpPtr
= (uint32_t*)((char*)(fHeader
) + sect
->offset() + reloc
->r_address());
5076 if ( reloc
->r_type() != ARM_RELOC_PAIR
)
5077 instruction
= LittleEndian::get32(*fixUpPtr
);
5079 if ( reloc
->r_extern() ) {
5080 const macho_nlist
<P
>* targetSymbol
= &fSymbols
[reloc
->r_symbolnum()];
5081 targetName
= &fStrings
[targetSymbol
->n_strx()];
5082 weakImport
= this->isWeakImportSymbol(targetSymbol
);
5085 switch ( reloc
->r_type() ) {
5086 case ARM_RELOC_BR24
:
5087 // Sign-extend displacement
5088 displacement
= (instruction
& 0x00FFFFFF) << 2;
5089 if ( (displacement
& 0x02000000) != 0 )
5090 displacement
|= 0xFC000000;
5091 // The pc added will be +8 from the pc
5093 // If this is BLX add H << 1
5094 if ((instruction
& 0xFE000000) == 0xFA000000)
5095 displacement
+= ((instruction
& 0x01000000) >> 23);
5097 if ( reloc
->r_extern() ) {
5098 uint32_t offsetInTarget
= srcAddr
+ displacement
;
5099 if ( strncmp(targetName
, "___dtrace_probe$", 16) == 0 ) {
5100 makeByNameReference(arm::kDtraceProbeSite
, srcAddr
, targetName
, 0);
5101 addDtraceExtraInfos(srcAddr
, &targetName
[16]);
5103 else if ( strncmp(targetName
, "___dtrace_isenabled$", 20) == 0 ) {
5104 makeByNameReference(arm::kDtraceIsEnabledSite
, srcAddr
, targetName
, 0);
5105 addDtraceExtraInfos(srcAddr
, &targetName
[20]);
5107 else if ( weakImport
)
5108 makeByNameReference(arm::kBranch24WeakImport
, srcAddr
, targetName
, offsetInTarget
);
5110 makeByNameReference(arm::kBranch24
, srcAddr
, targetName
, offsetInTarget
);
5113 dstAddr
= srcAddr
+ displacement
;
5114 ObjectFile::Atom
* atom
= findAtomAndOffset(dstAddr
).atom
;
5115 // check for dtrace probes and weak_import stubs
5116 const char* targetName
= atom
->getName();
5117 if ( (targetName
!= NULL
) && (strncmp(targetName
, "___dtrace_probe$", 16) == 0) ) {
5118 makeByNameReference(arm::kDtraceProbeSite
, srcAddr
, targetName
, 0);
5119 addDtraceExtraInfos(srcAddr
, &targetName
[16]);
5121 else if ( (targetName
!= NULL
) && (strncmp(targetName
, "___dtrace_isenabled$", 20) == 0) ) {
5122 makeByNameReference(arm::kDtraceIsEnabledSite
, srcAddr
, targetName
, 0);
5123 addDtraceExtraInfos(srcAddr
, &targetName
[20]);
5125 else if ( (atom
->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn
)
5126 && ((AnonymousAtom
<x86
>*)atom
)->isWeakImportStub() )
5127 makeReference(arm::kBranch24WeakImport
, srcAddr
, dstAddr
);
5128 else if ( reloc
->r_symbolnum() != R_ABS
)
5129 makeReference(arm::kBranch24
, srcAddr
, dstAddr
);
5131 // find absolute symbol that corresponds to pointerValue
5132 AddrToAtomMap::iterator pos
= fAddrToAbsoluteAtom
.find(dstAddr
);
5133 if ( pos
!= fAddrToAbsoluteAtom
.end() )
5134 makeByNameReference(arm::kBranch24
, srcAddr
, pos
->second
->getName(), 0);
5136 throwf("R_ABS reloc but no absolute symbol at target address");
5141 case ARM_THUMB_RELOC_BR22
:
5142 // thumb2 added two more bits to displacement, complicating the displacement decoding
5144 uint32_t s
= (instruction
>> 10) & 0x1;
5145 uint32_t j1
= (instruction
>> 29) & 0x1;
5146 uint32_t j2
= (instruction
>> 27) & 0x1;
5147 uint32_t imm10
= instruction
& 0x3FF;
5148 uint32_t imm11
= (instruction
>> 16) & 0x7FF;
5149 uint32_t i1
= (j1
== s
);
5150 uint32_t i2
= (j2
== s
);
5151 uint32_t dis
= (s
<< 24) | (i1
<< 23) | (i2
<< 22) | (imm10
<< 12) | (imm11
<< 1);
5155 displacement
= sdis
;
5157 // The pc added will be +4 from the pc
5159 // If the instruction was blx, force the low 2 bits to be clear
5160 dstAddr
= srcAddr
+ displacement
;
5161 if ((instruction
& 0xF8000000) == 0xE8000000)
5162 dstAddr
&= 0xFFFFFFFC;
5164 if ( reloc
->r_extern() ) {
5165 uint32_t offsetInTarget
= dstAddr
;
5166 if ( strncmp(targetName
, "___dtrace_probe$", 16) == 0 ) {
5167 makeByNameReference(arm::kDtraceProbeSite
, srcAddr
, targetName
, 0);
5168 addDtraceExtraInfos(srcAddr
, &targetName
[16]);
5170 else if ( strncmp(targetName
, "___dtrace_isenabled$", 20) == 0 ) {
5171 makeByNameReference(arm::kDtraceIsEnabledSite
, srcAddr
, targetName
, 0);
5172 addDtraceExtraInfos(srcAddr
, &targetName
[20]);
5174 else if ( weakImport
)
5175 makeByNameReference(arm::kThumbBranch22WeakImport
, srcAddr
, targetName
, offsetInTarget
);
5177 makeByNameReference(arm::kThumbBranch22
, srcAddr
, targetName
, offsetInTarget
);
5180 ObjectFile::Atom
* atom
= findAtomAndOffset(dstAddr
).atom
;
5181 // check for dtrace probes and weak_import stubs
5182 const char* targetName
= atom
->getName();
5183 if ( (targetName
!= NULL
) && (strncmp(targetName
, "___dtrace_probe$", 16) == 0) ) {
5184 makeByNameReference(arm::kDtraceProbeSite
, srcAddr
, targetName
, 0);
5185 addDtraceExtraInfos(srcAddr
, &targetName
[16]);
5187 else if ( (targetName
!= NULL
) && (strncmp(targetName
, "___dtrace_isenabled$", 20) == 0) ) {
5188 makeByNameReference(arm::kDtraceIsEnabledSite
, srcAddr
, targetName
, 0);
5189 addDtraceExtraInfos(srcAddr
, &targetName
[20]);
5191 else if ( (atom
->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn
)
5192 && ((AnonymousAtom
<x86
>*)atom
)->isWeakImportStub() )
5193 makeReference(arm::kThumbBranch22WeakImport
, srcAddr
, dstAddr
);
5194 else if ( reloc
->r_symbolnum() != R_ABS
)
5195 makeReference(arm::kThumbBranch22
, srcAddr
, dstAddr
);
5197 // find absolute symbol that corresponds to pointerValue
5198 AddrToAtomMap::iterator pos
= fAddrToAbsoluteAtom
.find(dstAddr
);
5199 if ( pos
!= fAddrToAbsoluteAtom
.end() )
5200 makeByNameReference(arm::kThumbBranch22
, srcAddr
, pos
->second
->getName(), 0);
5202 throwf("R_ABS reloc but no absolute symbol at target address");
5207 case ARM_RELOC_VANILLA
:
5208 if ( reloc
->r_length() != 2 )
5209 throw "bad length for ARM_RELOC_VANILLA";
5211 pointerValue
= instruction
;
5212 kind
= arm::kPointer
;
5213 if ( strcmp(sect
->segname(), "__TEXT") == 0 )
5214 kind
= arm::kReadOnlyPointer
;
5216 kind
= arm::kPointerWeakImport
;
5217 if ( reloc
->r_extern() ) {
5218 makeByNameReference(kind
, srcAddr
, targetName
, pointerValue
);
5221 AtomAndOffset at
= findAtomAndOffset(srcAddr
);
5222 AtomAndOffset to
= findAtomAndOffsetForSection(pointerValue
, reloc
->r_symbolnum());
5223 if ( to
.atom
->isThumb() )
5225 new Reference
<arm
>(kind
, at
, to
);
5229 case ARM_THUMB_32BIT_BRANCH
:
5230 // ignore old unnecessary relocs
5234 warning("unexpected relocation type %u", reloc
->r_type());
5239 const macho_scattered_relocation_info
<P
>* sreloc
= (macho_scattered_relocation_info
<P
>*)reloc
;
5240 const macho_scattered_relocation_info
<P
>* nextSReloc
= &sreloc
[1];
5241 srcAddr
= sect
->addr() + sreloc
->r_address();
5242 dstAddr
= sreloc
->r_value();
5243 uint32_t betterDstAddr
;
5244 fixUpPtr
= (uint32_t*)((char*)(fHeader
) + sect
->offset() + sreloc
->r_address());
5245 instruction
= LittleEndian::get32(*fixUpPtr
);
5247 // A ARM_RELOC_PAIR only follows ARM_RELOC_{SECTDIFF,LOCAL_SECTDIFF}
5248 // relocation types, and it is an error to see one otherwise.
5249 bool nextRelocIsPair
= false;
5250 uint32_t nextRelocAddress
= 0;
5251 uint32_t nextRelocValue
= 0;
5252 if ( nextSReloc
->r_type() == ARM_RELOC_PAIR
) {
5253 nextRelocIsPair
= true;
5254 nextRelocAddress
= nextSReloc
->r_address();
5255 nextRelocValue
= nextSReloc
->r_value();
5259 switch (sreloc
->r_type()) {
5260 case ARM_RELOC_VANILLA
:
5261 if ( sreloc
->r_length() != 2 )
5262 throw "bad length for ARM_RELOC_VANILLA";
5264 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
5265 betterDstAddr
= LittleEndian::get32(*fixUpPtr
);
5266 kind
= arm::kPointer
;
5267 if ( strcmp(sect
->segname(), "__TEXT") == 0 )
5268 kind
= arm::kReadOnlyPointer
;
5269 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
5270 makeReferenceWithToBase(kind
, srcAddr
, betterDstAddr
, dstAddr
);
5273 case ARM_RELOC_BR24
:
5274 // Sign-extend displacement
5275 displacement
= (instruction
& 0x00FFFFFF) << 2;
5276 if ( (displacement
& 0x02000000) != 0 )
5277 displacement
|= 0xFC000000;
5278 // The pc added will be +8 from the pc
5280 // If this is BLX add H << 1
5281 if ((instruction
& 0xFE000000) == 0xFA000000)
5282 displacement
+= ((instruction
& 0x01000000) >> 23);
5283 betterDstAddr
= srcAddr
+displacement
;
5284 makeReferenceWithToBase(arm::kBranch24
, srcAddr
, betterDstAddr
, dstAddr
);
5287 case ARM_THUMB_RELOC_BR22
:
5288 // thumb2 added two more bits to displacement, complicating the displacement decoding
5290 uint32_t s
= (instruction
>> 10) & 0x1;
5291 uint32_t j1
= (instruction
>> 29) & 0x1;
5292 uint32_t j2
= (instruction
>> 27) & 0x1;
5293 uint32_t imm10
= instruction
& 0x3FF;
5294 uint32_t imm11
= (instruction
>> 16) & 0x7FF;
5295 uint32_t i1
= (j1
== s
);
5296 uint32_t i2
= (j2
== s
);
5297 uint32_t dis
= (s
<< 24) | (i1
<< 23) | (i2
<< 22) | (imm10
<< 12) | (imm11
<< 1);
5301 displacement
= sdis
;
5303 // The pc added will be +4 from the pc
5305 betterDstAddr
= srcAddr
+displacement
;
5306 // If the instruction was blx, force the low 2 bits to be clear
5307 if ((instruction
& 0xF8000000) == 0xE8000000)
5308 betterDstAddr
&= 0xFFFFFFFC;
5309 makeReferenceWithToBase(arm::kThumbBranch22
, srcAddr
, betterDstAddr
, dstAddr
);
5312 case ARM_RELOC_SECTDIFF
:
5313 case ARM_RELOC_LOCAL_SECTDIFF
:
5314 if ( !nextRelocIsPair
) {
5315 throw "ARM_RELOC_SECTDIFF missing following pair";
5317 if ( sreloc
->r_length() != 2 )
5318 throw "bad length for ARM_RELOC_SECTDIFF";
5320 AtomAndOffset srcao
= findAtomAndOffset(srcAddr
);
5321 AtomAndOffset fromao
= findAtomAndOffset(nextRelocValue
);
5322 AtomAndOffset toao
= findAtomAndOffset(dstAddr
);
5323 // check for addend encoded in the section content
5324 pointerValue
= LittleEndian::get32(*fixUpPtr
);
5325 if ( (dstAddr
- nextRelocValue
) != pointerValue
) {
5326 if ( toao
.atom
== srcao
.atom
)
5327 toao
.offset
+= (pointerValue
+ nextRelocValue
) - dstAddr
;
5328 else if ( fromao
.atom
== srcao
.atom
)
5329 toao
.offset
+= (pointerValue
+ nextRelocValue
) - dstAddr
;
5331 fromao
.offset
+= (dstAddr
- pointerValue
) - nextRelocValue
;
5333 new Reference
<arm
>(arm::kPointerDiff
, srcao
, fromao
, toao
);
5338 warning("unexpected srelocation type %u", sreloc
->r_type());
5345 template <typename A
>
5346 void Reader
<A
>::addReferencesForSection(const macho_section
<P
>* sect
)
5348 // ignore dwarf sections. If ld ever supports processing dwarf, this logic will need to change
5349 if ( (sect
->flags() & S_ATTR_DEBUG
) == 0 ) {
5350 switch ( sect
->flags() & SECTION_TYPE
) {
5351 case S_SYMBOL_STUBS
:
5352 case S_LAZY_SYMBOL_POINTERS
:
5353 // we ignore compiler generated stubs, so ignore those relocs too
5356 // ignore all relocations in __eh_frame section
5357 if ( sect
== fehFrameSection
)
5359 const macho_relocation_info
<P
>* relocs
= (macho_relocation_info
<P
>*)((char*)(fHeader
) + sect
->reloff());
5360 const uint32_t relocCount
= sect
->nreloc();
5361 //fprintf(stderr, "relocCount = %d in section %s\n", relocCount, sect->sectname());
5362 for (uint32_t r
= 0; r
< relocCount
; ++r
) {
5364 if ( addRelocReference(sect
, &relocs
[r
]) )
5367 catch (const char* msg
) {
5368 throwf("in section %s,%s reloc %u: %s", sect
->segname(), sect
->sectname(), r
, msg
);
5377 const char* Reference
<x86
>::getDescription() const
5379 static char temp
[2048];
5382 sprintf(temp
, "reference to ");
5384 case x86::kFollowOn
:
5385 sprintf(temp
, "followed by ");
5387 case x86::kGroupSubordinate
:
5388 sprintf(temp
, "group subordinate ");
5390 case x86::kPointerWeakImport
:
5391 sprintf(temp
, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc
);
5394 sprintf(temp
, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc
);
5396 case x86::kPointerDiff
:
5398 // by-name references have quoted names
5399 const char* targetQuotes
= (&(this->getTarget()) == NULL
) ? "\"" : "";
5400 const char* fromQuotes
= (&(this->getFromTarget()) == NULL
) ? "\"" : "";
5401 sprintf(temp
, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
5402 fFixUpOffsetInSrc
, targetQuotes
, this->getTargetDisplayName(), targetQuotes
, fToTarget
.offset
,
5403 fromQuotes
, this->getFromTargetDisplayName(), fromQuotes
, fFromTarget
.offset
);
5407 case x86::kPointerDiff16
:
5409 // by-name references have quoted names
5410 const char* targetQuotes
= (&(this->getTarget()) == NULL
) ? "\"" : "";
5411 const char* fromQuotes
= (&(this->getFromTarget()) == NULL
) ? "\"" : "";
5412 sprintf(temp
, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
5413 fFixUpOffsetInSrc
, targetQuotes
, this->getTargetDisplayName(), targetQuotes
, fToTarget
.offset
,
5414 fromQuotes
, this->getFromTargetDisplayName(), fromQuotes
, fFromTarget
.offset
);
5418 case x86::kPCRel32WeakImport
:
5419 sprintf(temp
, "offset 0x%04X, rel32 reference to weak imported ", fFixUpOffsetInSrc
);
5422 sprintf(temp
, "offset 0x%04X, rel32 reference to ", fFixUpOffsetInSrc
);
5425 sprintf(temp
, "offset 0x%04X, rel16 reference to ", fFixUpOffsetInSrc
);
5428 sprintf(temp
, "offset 0x%04X, rel8 reference to ", fFixUpOffsetInSrc
);
5430 case x86::kAbsolute32
:
5431 sprintf(temp
, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc
);
5433 case x86::kImageOffset32
:
5434 sprintf(temp
, "offset 0x%04X, 32-bit offset of ", fFixUpOffsetInSrc
);
5436 case x86::kPointerDiff24
:
5437 sprintf(temp
, "offset 0x%04X, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)",
5438 fFixUpOffsetInSrc
, this->getTargetDisplayName(), fToTarget
.offset
,
5439 this->getFromTargetDisplayName(), fFromTarget
.offset
);
5442 case x86::kSectionOffset24
:
5443 sprintf(temp
, "offset 0x%04X, 24-bit section offset of ", fFixUpOffsetInSrc
);
5445 case x86::kDtraceProbe
:
5446 sprintf(temp
, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc
);
5448 case x86::kDtraceProbeSite
:
5449 sprintf(temp
, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc
);
5451 case x86::kDtraceIsEnabledSite
:
5452 sprintf(temp
, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc
);
5454 case x86::kDtraceTypeReference
:
5455 sprintf(temp
, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc
);
5458 // always quote by-name references
5459 if ( fToTargetName
!= NULL
) {
5461 strcat(temp
, fToTargetName
);
5464 else if ( fToTarget
.atom
!= NULL
) {
5465 strcat(temp
, fToTarget
.atom
->getDisplayName());
5468 strcat(temp
, "NULL target");
5470 if ( fToTarget
.offset
!= 0 )
5471 sprintf(&temp
[strlen(temp
)], " plus 0x%08X", fToTarget
.offset
);
5478 const char* Reference
<ppc
>::getDescription() const
5480 static char temp
[2048];
5483 sprintf(temp
, "reference to ");
5485 case ppc::kFollowOn
:
5486 sprintf(temp
, "followed by ");
5488 case ppc::kGroupSubordinate
:
5489 sprintf(temp
, "group subordinate ");
5491 case ppc::kPointerWeakImport
:
5492 sprintf(temp
, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc
);
5495 sprintf(temp
, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc
);
5497 case ppc::kPointerDiff16
:
5499 // by-name references have quoted names
5500 const char* targetQuotes
= (&(this->getTarget()) == NULL
) ? "\"" : "";
5501 const char* fromQuotes
= (&(this->getFromTarget()) == NULL
) ? "\"" : "";
5502 sprintf(temp
, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
5503 fFixUpOffsetInSrc
, targetQuotes
, this->getTargetDisplayName(), targetQuotes
, fToTarget
.offset
,
5504 fromQuotes
, this->getFromTargetDisplayName(), fromQuotes
, fFromTarget
.offset
);
5507 case ppc::kPointerDiff32
:
5509 // by-name references have quoted names
5510 const char* targetQuotes
= (&(this->getTarget()) == NULL
) ? "\"" : "";
5511 const char* fromQuotes
= (&(this->getFromTarget()) == NULL
) ? "\"" : "";
5512 sprintf(temp
, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
5513 fFixUpOffsetInSrc
, targetQuotes
, this->getTargetDisplayName(), targetQuotes
, fToTarget
.offset
,
5514 fromQuotes
, this->getFromTargetDisplayName(), fromQuotes
, fFromTarget
.offset
);
5517 case ppc::kPointerDiff64
:
5518 throw "unsupported refrence kind";
5520 case ppc::kBranch24WeakImport
:
5521 sprintf(temp
, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc
);
5523 case ppc::kBranch24
:
5524 case ppc::kBranch14
:
5525 sprintf(temp
, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc
);
5527 case ppc::kPICBaseLow16
:
5528 sprintf(temp
, "offset 0x%04X, low 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc
, fFromTarget
.atom
->getDisplayName(), fFromTarget
.offset
);
5530 case ppc::kPICBaseLow14
:
5531 sprintf(temp
, "offset 0x%04X, low 14 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc
, fFromTarget
.atom
->getDisplayName(), fFromTarget
.offset
);
5533 case ppc::kPICBaseHigh16
:
5534 sprintf(temp
, "offset 0x%04X, high 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc
, fFromTarget
.atom
->getDisplayName(), fFromTarget
.offset
);
5536 case ppc::kAbsLow16
:
5537 sprintf(temp
, "offset 0x%04X, low 16 fixup to absolute address of ", fFixUpOffsetInSrc
);
5539 case ppc::kAbsLow14
:
5540 sprintf(temp
, "offset 0x%04X, low 14 fixup to absolute address of ", fFixUpOffsetInSrc
);
5542 case ppc::kAbsHigh16
:
5543 sprintf(temp
, "offset 0x%04X, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc
);
5545 case ppc::kAbsHigh16AddLow
:
5546 sprintf(temp
, "offset 0x%04X, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc
);
5548 case ppc::kDtraceProbe
:
5549 sprintf(temp
, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc
);
5551 case ppc::kDtraceProbeSite
:
5552 sprintf(temp
, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc
);
5554 case ppc::kDtraceIsEnabledSite
:
5555 sprintf(temp
, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc
);
5557 case ppc::kDtraceTypeReference
:
5558 sprintf(temp
, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc
);
5561 // always quote by-name references
5562 if ( fToTargetName
!= NULL
) {
5564 strcat(temp
, fToTargetName
);
5567 else if ( fToTarget
.atom
!= NULL
) {
5568 strcat(temp
, fToTarget
.atom
->getDisplayName());
5571 strcat(temp
, "NULL target");
5573 if ( fToTarget
.offset
!= 0 )
5574 sprintf(&temp
[strlen(temp
)], " plus 0x%08X", fToTarget
.offset
);
5580 const char* Reference
<ppc64
>::getDescription() const
5582 static char temp
[2048];
5584 case ppc64::kNoFixUp
:
5585 sprintf(temp
, "reference to ");
5587 case ppc64::kFollowOn
:
5588 sprintf(temp
, "followed by ");
5590 case ppc64::kGroupSubordinate
:
5591 sprintf(temp
, "group subordinate ");
5593 case ppc64::kPointerWeakImport
:
5594 sprintf(temp
, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc
);
5596 case ppc64::kPointer
:
5597 sprintf(temp
, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc
);
5599 case ppc64::kPointerDiff64
:
5601 // by-name references have quoted names
5602 const char* targetQuotes
= (&(this->getTarget()) == NULL
) ? "\"" : "";
5603 const char* fromQuotes
= (&(this->getFromTarget()) == NULL
) ? "\"" : "";
5604 sprintf(temp
, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
5605 fFixUpOffsetInSrc
, targetQuotes
, this->getTargetDisplayName(), targetQuotes
, fToTarget
.offset
,
5606 fromQuotes
, this->getFromTargetDisplayName(), fromQuotes
, fFromTarget
.offset
);
5609 case ppc64::kPointerDiff32
:
5611 // by-name references have quoted names
5612 const char* targetQuotes
= (&(this->getTarget()) == NULL
) ? "\"" : "";
5613 const char* fromQuotes
= (&(this->getFromTarget()) == NULL
) ? "\"" : "";
5614 sprintf(temp
, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
5615 fFixUpOffsetInSrc
, targetQuotes
, this->getTargetDisplayName(), targetQuotes
, fToTarget
.offset
,
5616 fromQuotes
, this->getFromTargetDisplayName(), fromQuotes
, fFromTarget
.offset
);
5619 case ppc64::kPointerDiff16
:
5621 // by-name references have quoted names
5622 const char* targetQuotes
= (&(this->getTarget()) == NULL
) ? "\"" : "";
5623 const char* fromQuotes
= (&(this->getFromTarget()) == NULL
) ? "\"" : "";
5624 sprintf(temp
, "offset 0x%04llX, 16-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
5625 fFixUpOffsetInSrc
, targetQuotes
, this->getTargetDisplayName(), targetQuotes
, fToTarget
.offset
,
5626 fromQuotes
, this->getFromTargetDisplayName(), fromQuotes
, fFromTarget
.offset
);
5629 case ppc64::kBranch24WeakImport
:
5630 sprintf(temp
, "offset 0x%04llX, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc
);
5632 case ppc64::kBranch24
:
5633 case ppc64::kBranch14
:
5634 sprintf(temp
, "offset 0x%04llX, pc-rel branch fixup to ", fFixUpOffsetInSrc
);
5636 case ppc64::kPICBaseLow16
:
5637 sprintf(temp
, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc
, fFromTarget
.offset
);
5639 case ppc64::kPICBaseLow14
:
5640 sprintf(temp
, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc
, fFromTarget
.offset
);
5642 case ppc64::kPICBaseHigh16
:
5643 sprintf(temp
, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc
, fFromTarget
.offset
);
5645 case ppc64::kAbsLow16
:
5646 sprintf(temp
, "offset 0x%04llX, low 16 fixup to absolute address of ", fFixUpOffsetInSrc
);
5648 case ppc64::kAbsLow14
:
5649 sprintf(temp
, "offset 0x%04llX, low 14 fixup to absolute address of ", fFixUpOffsetInSrc
);
5651 case ppc64::kAbsHigh16
:
5652 sprintf(temp
, "offset 0x%04llX, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc
);
5654 case ppc64::kAbsHigh16AddLow
:
5655 sprintf(temp
, "offset 0x%04llX, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc
);
5657 case ppc64::kDtraceProbe
:
5658 sprintf(temp
, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc
);
5660 case ppc64::kDtraceProbeSite
:
5661 sprintf(temp
, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc
);
5663 case ppc64::kDtraceIsEnabledSite
:
5664 sprintf(temp
, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc
);
5666 case ppc64::kDtraceTypeReference
:
5667 sprintf(temp
, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc
);
5670 // always quote by-name references
5671 if ( fToTargetName
!= NULL
) {
5673 strcat(temp
, fToTargetName
);
5676 else if ( fToTarget
.atom
!= NULL
) {
5677 strcat(temp
, fToTarget
.atom
->getDisplayName());
5680 strcat(temp
, "NULL target");
5682 if ( fToTarget
.offset
!= 0 )
5683 sprintf(&temp
[strlen(temp
)], " plus 0x%llX", this->getTargetOffset());
5690 const char* Reference
<x86_64
>::getDescription() const
5692 static char temp
[2048];
5694 case x86_64::kNoFixUp
:
5695 sprintf(temp
, "reference to ");
5697 case x86_64::kFollowOn
:
5698 sprintf(temp
, "followed by ");
5700 case x86_64::kGroupSubordinate
:
5701 sprintf(temp
, "group subordinate ");
5703 case x86_64::kPointerWeakImport
:
5704 sprintf(temp
, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc
);
5706 case x86_64::kPointer
:
5707 sprintf(temp
, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc
);
5709 case x86_64::kPointer32
:
5710 sprintf(temp
, "offset 0x%04llX, 32-bit pointer to ", fFixUpOffsetInSrc
);
5712 case x86_64::kPointerDiff32
:
5713 case x86_64::kPointerDiff
:
5715 // by-name references have quoted names
5716 const char* targetQuotes
= (&(this->getTarget()) == NULL
) ? "\"" : "";
5717 const char* fromQuotes
= (&(this->getFromTarget()) == NULL
) ? "\"" : "";
5718 const char* size
= (fKind
== x86_64::kPointerDiff32
) ? "32-bit" : "64-bit";
5719 sprintf(temp
, "offset 0x%04llX, %s pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
5720 fFixUpOffsetInSrc
, size
, targetQuotes
, this->getTargetDisplayName(), targetQuotes
, fToTarget
.offset
,
5721 fromQuotes
, this->getFromTargetDisplayName(), fromQuotes
, fFromTarget
.offset
);
5725 case x86_64::kPCRel32
:
5726 sprintf(temp
, "offset 0x%04llX, rel32 reference to ", fFixUpOffsetInSrc
);
5728 case x86_64::kPCRel32_1
:
5729 sprintf(temp
, "offset 0x%04llX, rel32-1 reference to ", fFixUpOffsetInSrc
);
5731 case x86_64::kPCRel32_2
:
5732 sprintf(temp
, "offset 0x%04llX, rel32-2 reference to ", fFixUpOffsetInSrc
);
5734 case x86_64::kPCRel32_4
:
5735 sprintf(temp
, "offset 0x%04llX, rel32-4 reference to ", fFixUpOffsetInSrc
);
5737 case x86_64::kBranchPCRel32
:
5738 sprintf(temp
, "offset 0x%04llX, branch rel32 reference to ", fFixUpOffsetInSrc
);
5740 case x86_64::kBranchPCRel32WeakImport
:
5741 sprintf(temp
, "offset 0x%04llX, branch rel32 reference to weak imported ", fFixUpOffsetInSrc
);
5743 case x86_64::kPCRel32GOT
:
5744 sprintf(temp
, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc
);
5746 case x86_64::kPCRel32GOTWeakImport
:
5747 sprintf(temp
, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc
);
5749 case x86_64::kPCRel32GOTLoad
:
5750 sprintf(temp
, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc
);
5752 case x86_64::kPCRel32GOTLoadWeakImport
:
5753 sprintf(temp
, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc
);
5755 case x86_64::kGOTNoFixUp
:
5756 sprintf(temp
, "reference to GOT entry for ");
5758 case x86_64::kBranchPCRel8
:
5759 sprintf(temp
, "offset 0x%04llX, branch rel8 reference to ", fFixUpOffsetInSrc
);
5761 case x86_64::kPointerDiff24
:
5762 sprintf(temp
, "offset 0x%04llX, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)",
5763 fFixUpOffsetInSrc
, this->getTargetDisplayName(), fToTarget
.offset
,
5764 this->getFromTargetDisplayName(), fFromTarget
.offset
);
5766 case x86_64::kImageOffset32
:
5767 sprintf(temp
, "offset 0x%04llX, 32bit offset of ", fFixUpOffsetInSrc
);
5769 case x86_64::kSectionOffset24
:
5770 sprintf(temp
, "offset 0x%04llX, 24-bit section offset of ", fFixUpOffsetInSrc
);
5772 case x86_64::kDtraceProbe
:
5773 sprintf(temp
, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc
);
5775 case x86_64::kDtraceProbeSite
:
5776 sprintf(temp
, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc
);
5778 case x86_64::kDtraceIsEnabledSite
:
5779 sprintf(temp
, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc
);
5781 case x86_64::kDtraceTypeReference
:
5782 sprintf(temp
, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc
);
5785 // always quote by-name references
5786 if ( fToTargetName
!= NULL
) {
5788 strcat(temp
, fToTargetName
);
5791 else if ( fToTarget
.atom
!= NULL
) {
5792 strcat(temp
, fToTarget
.atom
->getDisplayName());
5795 strcat(temp
, "NULL target");
5797 if ( fToTarget
.offset
!= 0 )
5798 sprintf(&temp
[strlen(temp
)], " plus 0x%llX", this->getTargetOffset());
5805 const char* Reference
<arm
>::getDescription() const
5807 static char temp
[2048];
5810 sprintf(temp
, "reference to ");
5812 case arm::kFollowOn
:
5813 sprintf(temp
, "followed by ");
5815 case arm::kGroupSubordinate
:
5816 sprintf(temp
, "group subordinate ");
5819 sprintf(temp
, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc
);
5821 case arm::kPointerWeakImport
:
5822 sprintf(temp
, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc
);
5824 case arm::kPointerDiff
:
5826 // by-name references have quoted names
5827 const char* targetQuotes
= (&(this->getTarget()) == NULL
) ? "\"" : "";
5828 const char* fromQuotes
= (&(this->getFromTarget()) == NULL
) ? "\"" : "";
5829 sprintf(temp
, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
5830 fFixUpOffsetInSrc
, targetQuotes
, this->getTargetDisplayName(), targetQuotes
, fToTarget
.offset
,
5831 fromQuotes
, this->getFromTargetDisplayName(), fromQuotes
, fFromTarget
.offset
);
5834 case arm::kPointerDiff12
:
5836 // by-name references have quoted names
5837 const char* targetQuotes
= (&(this->getTarget()) == NULL
) ? "\"" : "";
5838 const char* fromQuotes
= (&(this->getFromTarget()) == NULL
) ? "\"" : "";
5839 sprintf(temp
, "offset 0x%04X, 12-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
5840 fFixUpOffsetInSrc
, targetQuotes
, this->getTargetDisplayName(), targetQuotes
, fToTarget
.offset
,
5841 fromQuotes
, this->getFromTargetDisplayName(), fromQuotes
, fFromTarget
.offset
);
5844 case arm::kReadOnlyPointer
:
5845 sprintf(temp
, "offset 0x%04X, read-only pointer to ", fFixUpOffsetInSrc
);
5847 case arm::kBranch24
:
5848 case arm::kThumbBranch22
:
5849 sprintf(temp
, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc
);
5851 case arm::kBranch24WeakImport
:
5852 case arm::kThumbBranch22WeakImport
:
5853 sprintf(temp
, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc
);
5855 case arm::kDtraceProbe
:
5856 sprintf(temp
, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc
);
5858 case arm::kDtraceProbeSite
:
5859 sprintf(temp
, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc
);
5861 case arm::kDtraceIsEnabledSite
:
5862 sprintf(temp
, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc
);
5864 case arm::kDtraceTypeReference
:
5865 sprintf(temp
, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc
);
5868 // always quote by-name references
5869 if ( fToTargetName
!= NULL
) {
5871 strcat(temp
, fToTargetName
);
5874 else if ( fToTarget
.atom
!= NULL
) {
5875 strcat(temp
, fToTarget
.atom
->getDisplayName());
5878 strcat(temp
, "NULL target");
5880 if ( fToTarget
.offset
!= 0 )
5881 sprintf(&temp
[strlen(temp
)], " plus 0x%08X", fToTarget
.offset
);
5888 bool Reference
<x86
>::isBranch() const
5892 case x86::kPCRel32WeakImport
:
5900 bool Reference
<x86_64
>::isBranch() const
5903 case x86_64::kBranchPCRel32
:
5904 case x86_64::kBranchPCRel32WeakImport
:
5912 bool Reference
<ppc
>::isBranch() const
5915 case ppc::kBranch24
:
5916 case ppc::kBranch24WeakImport
:
5924 bool Reference
<ppc64
>::isBranch() const
5927 case ppc64::kBranch24
:
5928 case ppc64::kBranch24WeakImport
:
5936 bool Reference
<arm
>::isBranch() const
5939 case arm::kBranch24
:
5940 case arm::kBranch24WeakImport
:
5941 case arm::kThumbBranch22
:
5942 case arm::kThumbBranch22WeakImport
:
5951 }; // namespace relocatable
5952 }; // namespace mach_o
5954 #endif // __OBJECT_FILE_MACH_O__