2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- */
26 namespace ObjectFileMachO
{
28 class Reference
: public ObjectFile::Reference
31 Reference(macho_uintptr_t fixUpOffset
, Kind kind
, const char* targetName
, uint64_t offsetInTarget
, uint64_t offsetInFromTarget
);
32 Reference(macho_uintptr_t fixUpOffset
, Kind kind
, class Atom
& target
, uint64_t offsetInTarget
, uint64_t offsetInFromTarget
);
33 Reference(macho_uintptr_t fixUpOffset
, Kind kind
, class Atom
& target
, uint64_t offsetInTarget
, class Atom
& fromTarget
, uint64_t offsetInFromTarget
);
37 virtual bool isUnbound() const;
38 virtual bool isWeakReference() const;
39 virtual bool requiresRuntimeFixUp() const;
40 virtual bool isLazyReference() const;
41 virtual Kind
getKind() const;
42 virtual uint64_t getFixUpOffset() const;
43 virtual const char* getTargetName() const;
44 virtual ObjectFile::Atom
& getTarget() const;
45 virtual uint64_t getTargetOffset() const;
46 virtual ObjectFile::Atom
& getFromTarget() const;
47 virtual const char* getFromTargetName() const;
48 virtual void setTarget(ObjectFile::Atom
&);
49 virtual void setFromTarget(ObjectFile::Atom
&);
50 virtual void setFromTargetName(const char*);
51 virtual const char* getDescription() const;
52 virtual uint64_t getFromTargetOffset() const;
57 ObjectFile::Atom
* fTarget
;
58 ObjectFile::Atom
* fFromTarget
;
59 const char* fTargetName
;
60 const char* fFromTargetName
;
61 macho_uintptr_t fTargetOffset
;
62 macho_uintptr_t fFromTargetOffset
;
63 macho_uintptr_t fFixUpOffsetInSrc
;
71 class Reader
: public ObjectFile::Reader
74 Reader(const char* path
);
75 Reader(const macho_header
* header
, const char* path
, const ObjectFile::ReaderOptions
& options
);
78 virtual const char* getPath();
79 virtual std::vector
<class ObjectFile::Atom
*>& getAtoms();
80 virtual std::vector
<class ObjectFile::Atom
*>* getJustInTimeAtomsFor(const char* name
);
81 virtual std::vector
<ObjectFile::StabsInfo
>* getStabsDebugInfo(); // stabs info not associated with an atom
86 void init(const macho_header
* header
, const char* path
);
87 void buildOffsetsSet(const macho_relocation_info
* reloc
, const macho_section
* sect
, std::set
<uint32_t>& offsets
, std::set
<uint32_t>& dontUse
);
88 void addRelocReference(const macho_section
* sect
, const macho_relocation_info
* reloc
);
89 Atom
* findAtomCoveringOffset(uint32_t offset
);
90 uint32_t findAtomIndex(const Atom
& atom
);
91 void addFixUp(uint32_t srcAddr
, uint32_t dstAddr
, Reference::Kind kind
, uint32_t picBaseAddr
);
92 class Segment
* makeSegmentFromSection(const macho_section
*);
93 macho_uintptr_t
commonsOffset();
94 void insertOffsetIfText(std::set
<uint32_t>& offsets
, uint32_t value
);
95 void insertOffsetIfNotText(std::set
<uint32_t>& offsets
, uint32_t value
);
96 const macho_section
* findSectionCoveringOffset(uint32_t offset
);
97 void addCallSiteReference(Atom
& src
, uint32_t offsetInSrcAtom
, Reference::Kind kind
, Atom
& target
, uint32_t picBaseOffset
, uint32_t offsetInTargetAtom
);
98 void deadStub(Atom
& target
);
101 const ObjectFile::ReaderOptions
& fOptions
;
102 const macho_header
* fHeader
;
103 const char* fStrings
;
104 const macho_nlist
* fSymbols
;
105 uint32_t fSymbolCount
;
106 const macho_segment_command
* fSegment
;
107 const uint32_t* fIndirectTable
;
108 std::vector
<class Atom
*> fAtoms
;
109 std::vector
<class Segment
*> fSegments
;
110 std::set
<class ObjectFile::Atom
*> fDeadAtoms
;
111 uint32_t fNonAtomStabsStartIndex
;
112 uint32_t fNonAtomStabsCount
;
113 std::vector
<uint32_t> fNonAtomExtras
;
116 class Segment
: public ObjectFile::Segment
119 virtual const char* getName() const;
120 virtual bool isContentReadable() const;
121 virtual bool isContentWritable() const;
122 virtual bool isContentExecutable() const;
124 Segment(const macho_section
*);
127 const macho_section
* fSection
;
130 class Atom
: public ObjectFile::Atom
133 virtual ObjectFile::Reader
* getFile() const;
134 virtual const char* getName() const;
135 virtual const char* getDisplayName() const;
136 virtual Scope
getScope() const;
137 virtual bool isTentativeDefinition() const;
138 virtual bool isWeakDefinition() const;
139 virtual bool isCoalesableByName() const;
140 virtual bool isCoalesableByValue() const;
141 virtual bool isZeroFill() const;
142 virtual bool dontDeadStrip() const;
143 virtual bool dontStripName() const; // referenced dynamically
144 virtual bool isImportProxy() const;
145 virtual uint64_t getSize() const;
146 virtual std::vector
<ObjectFile::Reference
*>& getReferences() const;
147 virtual bool mustRemainInSection() const;
148 virtual const char* getSectionName() const;
149 virtual Segment
& getSegment() const;
150 virtual bool requiresFollowOnAtom() const;
151 virtual ObjectFile::Atom
& getFollowOnAtom() const;
152 virtual std::vector
<ObjectFile::StabsInfo
>* getStabsDebugInfo() const;
153 virtual uint8_t getAlignment() const;
154 virtual WeakImportSetting
getImportWeakness() const { return ObjectFile::Atom::kWeakUnset
; }
155 virtual void copyRawContent(uint8_t buffer
[]) const;
156 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
157 virtual void setScope(Scope
);
158 virtual void setImportWeakness(bool weakImport
) { }
164 Atom(Reader
&, const macho_nlist
*);
165 Atom(Reader
&, uint32_t offset
);
168 const macho_section
* findSectionFromOffset(macho_uintptr_t offset
);
169 const macho_section
* getCommonsSection();
170 void setSize(macho_uintptr_t
);
171 void setFollowOnAtom(Atom
&);
172 static bool atomCompare(const Atom
* lhs
, const Atom
* rhs
);
173 Reference
* addDirectReference(macho_uintptr_t offsetInSrcAtom
, Reference::Kind kind
, Atom
& target
, uint64_t offsetInTarget
, uint64_t offsetInFromTarget
);
174 Reference
* addByNameReference(macho_uintptr_t offsetInSrcAtom
, Reference::Kind kind
, const char* targetName
, uint64_t offsetInTarget
, uint64_t offsetInFromTarget
);
175 Reference
* addDifferenceReference(macho_uintptr_t offsetInSrcAtom
, Reference::Kind kind
, Atom
& target
, uint64_t offsetInTarget
, Atom
& fromTarget
, uint64_t offsetInFromTarget
);
176 Reference
* addReference(macho_uintptr_t offsetInSrcAtom
, Reference::Kind kind
, Atom
& target
, uint64_t offsetInTarget
, uint64_t offsetInFromTarget
);
179 const macho_nlist
* fSymbol
;
180 macho_uintptr_t fOffset
;
181 macho_uintptr_t fSize
;
182 const macho_section
* fSection
;
184 const char* fSynthesizedName
;
185 std::vector
<class Reference
*> fReferences
;
186 ObjectFile::Atom::Scope fScope
;
187 uint32_t fStabsStartIndex
;
188 uint32_t fStabsCount
;
190 static macho_section fgCommonsSection
; // for us by tentative definitions
194 Reader
* MakeReader(const macho_header
* mh
, const char* path
, const ObjectFile::ReaderOptions
& options
)
196 return new Reader(mh
, path
, options
);
200 Reader::Reader(const macho_header
* header
, const char* path
, const ObjectFile::ReaderOptions
& options
)
201 : fPath(NULL
), fOptions(options
), fHeader(NULL
), fStrings(NULL
), fSymbols(NULL
), fSymbolCount(0), fSegment(NULL
)
206 Reader::Reader(const char* path
)
207 : fPath(NULL
), fOptions(*(new ObjectFile::ReaderOptions())), fHeader(NULL
), fStrings(NULL
), fSymbols(NULL
), fSymbolCount(0), fSegment(NULL
),
208 fNonAtomStabsStartIndex(0), fNonAtomStabsCount(0)
210 struct stat stat_buf
;
212 int fd
= ::open(path
, O_RDONLY
, 0);
213 ::fstat(fd
, &stat_buf
);
214 void* p
= ::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
, fd
, 0);
216 if ( ((macho_header
*)p
)->magic() == MH_MAGIC
) {
217 init((macho_header
*)p
, path
);
220 throw "add fat handling";
229 bool Atom::atomCompare(const Atom
* lhs
, const Atom
* rhs
)
231 return lhs
->fOffset
< rhs
->fOffset
;
236 void Reader::init(const macho_header
* header
, const char* path
)
239 #if defined(ARCH_PPC)
240 if ( (header
->magic() != MH_MAGIC
) || (header
->cputype() != CPU_TYPE_POWERPC
) )
241 throw "not a valid ppc mach-o file";
242 #elif defined(ARCH_I386)
243 if ( (header
->magic() != MH_MAGIC
) || (header
->cputype() != CPU_TYPE_I386
) )
244 throw "not a valid i386 mach-o file";
245 #elif defined(ARCH_PPC64)
246 if ( (header
->magic() != MH_MAGIC_64
) || (header
->cputype() != CPU_TYPE_POWERPC64
) )
247 throw "not a valid ppc64 mach-o file";
250 // cache intersting pointers
251 fPath
= strdup(path
);
253 const uint32_t cmd_count
= header
->ncmds();
254 const macho_load_command
* const cmds
= (macho_load_command
*)((char*)header
+ macho_header::size
);
255 const macho_load_command
* cmd
= cmds
;
256 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
257 switch (cmd
->cmd()) {
260 const macho_symtab_command
* symtab
= (macho_symtab_command
*)cmd
;
261 fSymbolCount
= symtab
->nsyms();
262 fSymbols
= (const macho_nlist
*)((char*)header
+ symtab
->symoff());
263 fStrings
= (char*)header
+ symtab
->stroff();
268 const macho_dysymtab_command
* dsymtab
= (struct macho_dysymtab_command
*)cmd
;
269 fIndirectTable
= (uint32_t*)((char*)fHeader
+ dsymtab
->indirectsymoff());
273 if ( cmd
->cmd() == macho_segment_command::command
) {
274 fSegment
= (macho_segment_command
*)cmd
;
278 cmd
= (const macho_load_command
*)(((char*)cmd
)+cmd
->cmdsize());
281 // add all atoms that have entries in symbol table
282 std::set
<uint32_t> symbolAtomOffsets
;
283 for (uint32_t i
=0; i
< fSymbolCount
; ++i
) {
284 const macho_nlist
& sym
= fSymbols
[i
];
285 if ( (sym
.n_type() & N_STAB
) == 0 ) {
286 uint8_t type
= (sym
.n_type() & N_TYPE
);
287 if ( (type
== N_SECT
) || ((type
== N_UNDF
) && (sym
.n_value() != 0)) ) {
288 // real definition or "tentative definition"
289 Atom
* newAtom
= new Atom(*this, &sym
);
290 fAtoms
.push_back(newAtom
);
291 symbolAtomOffsets
.insert(newAtom
->fOffset
);
296 // add all points referenced in relocations
297 const macho_section
* const sectionsStart
= (macho_section
*)((char*)fSegment
+ sizeof(macho_segment_command
));
298 const macho_section
* const sectionsEnd
= §ionsStart
[fSegment
->nsects()];
299 std::set
<uint32_t> cleavePoints
;
300 std::set
<uint32_t> dontCleavePoints
;
301 for (const macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
302 const macho_relocation_info
* relocs
= (macho_relocation_info
*)((char*)(fHeader
) + sect
->reloff());
303 const uint32_t relocCount
= sect
->nreloc();
304 for (uint32_t r
= 0; r
< relocCount
; ++r
) {
305 buildOffsetsSet(&relocs
[r
], sect
, cleavePoints
, dontCleavePoints
);
308 // add all stub functions and (non)lazy pointers
309 std::set
<uint32_t> deadStubOffsets
;
310 for (const macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
311 uint8_t type (sect
->flags() & SECTION_TYPE
);
315 const uint32_t stubSize
= sect
->reserved2();
316 // TVector glue sections are marked as S_SYMBOL_STUBS but are only 8 bytes
317 if ( stubSize
> 8 ) {
318 for(uint32_t sectOffset
=0; sectOffset
< sect
->size(); sectOffset
+= stubSize
) {
319 uint32_t stubAddr
= sect
->addr() + sectOffset
;
320 if ( cleavePoints
.count(stubAddr
) == 0 ) {
321 cleavePoints
.insert(stubAddr
);
322 deadStubOffsets
.insert(stubAddr
);
328 case S_NON_LAZY_SYMBOL_POINTERS
:
329 case S_LAZY_SYMBOL_POINTERS
:
330 for(uint32_t sectOffset
=0; sectOffset
< sect
->size(); sectOffset
+= sizeof(macho_uintptr_t
)) {
331 uint32_t pointerAddr
= sect
->addr() + sectOffset
;
332 cleavePoints
.insert(pointerAddr
);
336 // also make sure each section break is a cleave point
337 if ( sect
->size() != 0 )
338 cleavePoints
.insert(sect
->addr());
341 for (std::set
<uint32_t>::iterator it
=cleavePoints
.begin(); it
!= cleavePoints
.end(); it
++) {
342 uint32_t cleavePoint
= *it
;
343 //printf("cleave offset 0x%08X\n", cleavePoint);
344 // only create an atom if it is not a don't-cleave point and there is not already an atom at this offset
345 if ( (dontCleavePoints
.count(cleavePoint
) == 0) && (symbolAtomOffsets
.count(cleavePoint
) == 0) )
346 fAtoms
.push_back(new Atom(*this, cleavePoint
));
349 const uint32_t atomCount
= fAtoms
.size();
350 if ( atomCount
> 0 ) {
351 // sort the atoms so the occur in source file order
352 std::sort(fAtoms
.begin(), fAtoms
.end(), Atom::atomCompare
);
354 // tell each atom its size and follow on
355 const bool dontDeadStrip
= ((fHeader
->flags() & MH_SUBSECTIONS_VIA_SYMBOLS
) == 0);
356 Atom
* lastAtom
= fAtoms
[0];
357 for (uint32_t i
=1; i
< atomCount
; ++i
) {
358 Atom
* thisAtom
= fAtoms
[i
];
359 if ( lastAtom
->getSize() == 0 ) {
360 if ( lastAtom
->fSection
== thisAtom
->fSection
)
361 lastAtom
->setSize(thisAtom
->fOffset
- lastAtom
->fOffset
);
363 lastAtom
->setSize(lastAtom
->fSection
->addr() + lastAtom
->fSection
->size() - lastAtom
->fOffset
);
366 lastAtom
->setFollowOnAtom(*thisAtom
);
369 lastAtom
= fAtoms
[atomCount
-1];
370 if ( lastAtom
->getSize() == 0 )
371 lastAtom
->setSize(lastAtom
->fSection
->addr() + lastAtom
->fSection
->size() - lastAtom
->fOffset
);
373 // add relocation based references
374 for (const macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
375 const macho_relocation_info
* relocs
= (macho_relocation_info
*)((char*)(fHeader
) + sect
->reloff());
376 const uint32_t relocCount
= sect
->nreloc();
377 for (uint32_t r
= 0; r
< relocCount
; ++r
) {
378 addRelocReference(sect
, &relocs
[r
]);
382 // add dead stubs to list to delete
383 for (std::set
<uint32_t>::iterator it
=deadStubOffsets
.begin(); it
!= deadStubOffsets
.end(); it
++) {
384 Atom
* deadStub
= findAtomCoveringOffset(*it
);
385 this->deadStub(*deadStub
);
388 // remove dead stubs and lazy pointers
389 for (std::set
<ObjectFile::Atom
*>::iterator deadIt
=fDeadAtoms
.begin(); deadIt
!= fDeadAtoms
.end(); deadIt
++) {
390 for (std::vector
<Atom
*>::iterator it
=fAtoms
.begin(); it
!= fAtoms
.end(); it
++) {
391 if ( *deadIt
== *it
) {
399 // process stabs debugging info
400 if ( ! fOptions
.fStripDebugInfo
) {
401 // scan symbol table for stabs entries
402 fNonAtomStabsStartIndex
= 0xFFFFFFFF;
403 fNonAtomStabsCount
= 0;
404 uint32_t possibleStart
= 0;
406 const uint32_t atomCount
= fAtoms
.size();
407 enum { start
, inBeginEnd
, foundFirst
, inFunction
} state
= start
;
408 for (uint32_t symbolIndex
= 0; symbolIndex
< fSymbolCount
; ++symbolIndex
) {
409 const macho_nlist
* sym
= &fSymbols
[symbolIndex
];
410 uint8_t type
= sym
->n_type();
411 if ( (type
& N_STAB
) != 0 ) {
412 if ( fNonAtomStabsStartIndex
== 0xFFFFFFFF )
413 fNonAtomStabsStartIndex
= symbolIndex
;
416 if ( (type
== N_SLINE
) || (type
== N_SOL
) ) {
417 possibleStart
= symbolIndex
;
420 else if ( type
== N_BNSYM
) {
421 macho_uintptr_t targetAddr
= sym
->n_value();
422 atom
= this->findAtomCoveringOffset(targetAddr
);
423 if ( (atom
!= NULL
) || (atom
->fOffset
== targetAddr
) ) {
424 atom
->fStabsStartIndex
= symbolIndex
;
425 if ( fNonAtomStabsCount
== 0 )
426 fNonAtomStabsCount
= symbolIndex
- fNonAtomStabsStartIndex
;
429 fprintf(stderr
, "can't find atom for stabs 0x%02X at %08X in %s\n", type
, targetAddr
, path
);
434 else if ( (type
== N_STSYM
) || (type
== N_LCSYM
) ) {
435 macho_uintptr_t targetAddr
= sym
->n_value();
436 atom
= this->findAtomCoveringOffset(targetAddr
);
437 if ( (atom
!= NULL
) || (atom
->fOffset
== targetAddr
) ) {
438 atom
->fStabsStartIndex
= symbolIndex
;
439 atom
->fStabsCount
= 1;
440 if ( fNonAtomStabsCount
== 0 )
441 fNonAtomStabsCount
= symbolIndex
- fNonAtomStabsStartIndex
;
444 fprintf(stderr
, "can't find atom for stabs 0x%02X at %08X in %s\n", type
, targetAddr
, path
);
448 else if ( type
== N_GSYM
) {
449 // n_value field is NOT atom address ;-(
450 // need to find atom by name match
451 const char* symString
= &fStrings
[sym
->n_strx()];
452 const char* colon
= strchr(symString
, ':');
454 if ( colon
!= NULL
) {
455 int nameLen
= colon
- symString
;
456 for (uint32_t searchIndex
= 0; searchIndex
< atomCount
; ++searchIndex
) {
457 const char* atomName
= fAtoms
[searchIndex
]->getName();
458 if ( (atomName
!= NULL
) && (strncmp(&atomName
[1], symString
, nameLen
) == 0) ) {
459 atom
= fAtoms
[searchIndex
];
460 atom
->fStabsStartIndex
= symbolIndex
;
461 atom
->fStabsCount
= 1;
462 if ( fNonAtomStabsCount
== 0 )
463 fNonAtomStabsCount
= symbolIndex
- fNonAtomStabsStartIndex
;
470 fprintf(stderr
, "can't find atom for N_GSYM stabs %s in %s\n", symString
, path
);
474 else if ( type
== N_LSYM
) {
475 if ( fNonAtomStabsCount
!= 0 ) {
476 // built with -gfull and some type definition not at start of source
477 fNonAtomExtras
.push_back(symbolIndex
);
482 if ( type
== N_ENSYM
) {
485 atom
->fStabsCount
= symbolIndex
- atom
->fStabsStartIndex
+ 1;
489 if ( (type
== N_FUN
) && (sym
->n_sect() != 0) ) {
491 macho_uintptr_t targetAddr
= sym
->n_value();
492 atom
= this->findAtomCoveringOffset(targetAddr
);
493 if ( (atom
== NULL
) || (atom
->fOffset
!= targetAddr
) ) {
494 fprintf(stderr
, "can't find atom for stabs FUN index: %d at 0x%08llX in %s\n", symbolIndex
, (uint64_t)targetAddr
, path
);
498 atom
->fStabsStartIndex
= possibleStart
;
499 if ( fNonAtomStabsCount
== 0 )
500 fNonAtomStabsCount
= possibleStart
- fNonAtomStabsStartIndex
;
503 else if ( (type
== N_FUN
) && (sym
->n_sect() == 0) ) {
504 fprintf(stderr
, "end stab FUN found without start FUN, index=%d in %s\n", symbolIndex
, path
);
509 if ( (type
== N_FUN
) && (sym
->n_sect() == 0) ) {
512 atom
->fStabsCount
= symbolIndex
- atom
->fStabsStartIndex
+ 1;
523 void Reader::addRelocReference(const macho_section
* sect
, const macho_relocation_info
* reloc
)
529 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
530 uint32_t instruction
;
533 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
534 fixUpPtr
= (uint32_t*)((char*)(fHeader
) + sect
->offset() + reloc
->r_address());
535 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
536 const macho_relocation_info
* nextReloc
= &reloc
[1];
538 switch ( reloc
->r_type() ) {
539 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
542 if ( reloc
->r_extern() ) {
543 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
544 int32_t displacement
= (instruction
& 0x03FFFFFC);
545 if ( (displacement
& 0x02000000) != 0 )
546 displacement
|= 0xFC000000;
547 uint32_t offsetInTarget
= sect
->addr() + reloc
->r_address() + displacement
;
548 srcAddr
= sect
->addr() + reloc
->r_address();
549 src
= findAtomCoveringOffset(srcAddr
);
550 const macho_nlist
* targetSymbol
= &fSymbols
[reloc
->r_symbolnum()];
551 const char* targetName
= &fStrings
[targetSymbol
->n_strx()];
552 src
->addByNameReference(srcAddr
- src
->fOffset
, Reference::ppcFixupBranch24
, targetName
, offsetInTarget
, 0);
555 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
556 if ( (instruction
& 0x4C000000) == 0x48000000 ) {
557 int32_t displacement
= (instruction
& 0x03FFFFFC);
558 if ( (displacement
& 0x02000000) != 0 )
559 displacement
|= 0xFC000000;
560 srcAddr
= sect
->addr() + reloc
->r_address();
561 dstAddr
= srcAddr
+ displacement
;
562 src
= findAtomCoveringOffset(srcAddr
);
563 dst
= findAtomCoveringOffset(dstAddr
);
564 this->addCallSiteReference(*src
, srcAddr
- src
->fOffset
, Reference::ppcFixupBranch24
, *dst
, 0, dstAddr
- dst
->fOffset
);
571 if ( reloc
->r_extern() ) {
572 srcAddr
= sect
->addr() + reloc
->r_address();
573 src
= findAtomCoveringOffset(srcAddr
);
574 const macho_nlist
* targetSymbol
= &fSymbols
[reloc
->r_symbolnum()];
575 const char* targetName
= &fStrings
[targetSymbol
->n_strx()];
576 src
->addByNameReference(srcAddr
- src
->fOffset
, Reference::ppcFixupBranch14
, targetName
, 0, 0);
579 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
580 int32_t displacement
= (instruction
& 0x0000FFFC);
581 if ( (displacement
& 0x00008000) != 0 )
582 displacement
|= 0xFFFF0000;
583 srcAddr
= sect
->addr() + reloc
->r_address();
584 dstAddr
= srcAddr
+ displacement
;
585 src
= findAtomCoveringOffset(srcAddr
);
586 dst
= findAtomCoveringOffset(dstAddr
);
587 this->addCallSiteReference(*src
, srcAddr
- src
->fOffset
, Reference::ppcFixupBranch14
, *dst
, 0, dstAddr
- dst
->fOffset
);
592 // skip, processed by a previous look ahead
596 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
597 printf("PPC_RELOC_LO16 missing following pair\n");
600 srcAddr
= sect
->addr() + reloc
->r_address();
601 if ( reloc
->r_extern() ) {
602 const macho_nlist
* targetSymbol
= &fSymbols
[reloc
->r_symbolnum()];
603 const char* targetName
= &fStrings
[targetSymbol
->n_strx()];
604 src
= findAtomCoveringOffset(srcAddr
);
605 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
606 dstAddr
= (nextReloc
->r_address() << 16) | (instruction
& 0x0000FFFF);
607 src
->addByNameReference(srcAddr
- src
->fOffset
, Reference::ppcFixupAbsLow16
, targetName
, dstAddr
, 0);
610 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
611 int16_t lowBits
= (instruction
& 0xFFFF);
612 dstAddr
= (nextReloc
->r_address() << 16) + (int32_t)lowBits
;
613 if ( (lowBits
& 0x8000) != 0 )
615 addFixUp(srcAddr
, dstAddr
, Reference::ppcFixupAbsLow16
, 0);
621 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
622 printf("PPC_RELOC_LO14 missing following pair\n");
625 srcAddr
= sect
->addr() + reloc
->r_address();
626 if ( reloc
->r_extern() ) {
627 const macho_nlist
* targetSymbol
= &fSymbols
[reloc
->r_symbolnum()];
628 const char* targetName
= &fStrings
[targetSymbol
->n_strx()];
629 src
= findAtomCoveringOffset(srcAddr
);
630 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
631 dstAddr
= (nextReloc
->r_address() << 16) | (instruction
& 0x0000FFFC);
632 src
->addByNameReference(srcAddr
- src
->fOffset
, Reference::ppcFixupAbsLow14
, targetName
, dstAddr
, 0);
635 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
636 dstAddr
= (nextReloc
->r_address() << 16) | (instruction
& 0x0000FFFC);
637 addFixUp(srcAddr
, dstAddr
, Reference::ppcFixupAbsLow14
, 0);
643 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
644 printf("PPC_RELOC_HI16 missing following pair\n");
647 srcAddr
= sect
->addr() + reloc
->r_address();
648 if ( reloc
->r_extern() ) {
649 const macho_nlist
* targetSymbol
= &fSymbols
[reloc
->r_symbolnum()];
650 const char* targetName
= &fStrings
[targetSymbol
->n_strx()];
651 src
= findAtomCoveringOffset(srcAddr
);
652 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
653 dstAddr
= ((instruction
& 0x0000FFFF) << 16) | (nextReloc
->r_address() & 0x0000FFFF);
654 src
->addByNameReference(srcAddr
- src
->fOffset
, Reference::ppcFixupAbsHigh16
, targetName
, dstAddr
, 0);
657 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
658 dstAddr
= ((instruction
& 0x0000FFFF) << 16) | (nextReloc
->r_address() & 0x0000FFFF);
659 addFixUp(srcAddr
, dstAddr
, Reference::ppcFixupAbsHigh16
, 0);
665 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
666 printf("PPC_RELOC_HA16 missing following pair\n");
669 srcAddr
= sect
->addr() + reloc
->r_address();
670 if ( reloc
->r_extern() ) {
671 const macho_nlist
* targetSymbol
= &fSymbols
[reloc
->r_symbolnum()];
672 const char* targetName
= &fStrings
[targetSymbol
->n_strx()];
673 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
674 int16_t lowBits
= (nextReloc
->r_address() & 0x0000FFFF);
675 dstAddr
= ((instruction
& 0x0000FFFF) << 16) + (int32_t)lowBits
;
676 src
= findAtomCoveringOffset(srcAddr
);
677 src
->addByNameReference(srcAddr
- src
->fOffset
, Reference::ppcFixupAbsHigh16AddLow
, targetName
, dstAddr
, 0);
680 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
681 int16_t lowBits
= (nextReloc
->r_address() & 0x0000FFFF);
682 dstAddr
= ((instruction
& 0x0000FFFF) << 16) + (int32_t)lowBits
;
683 addFixUp(srcAddr
, dstAddr
, Reference::ppcFixupAbsHigh16AddLow
, 0);
687 case GENERIC_RELOC_VANILLA
:
689 srcAddr
= sect
->addr() + reloc
->r_address();
690 Atom
* srcAtom
= findAtomCoveringOffset(srcAddr
);
691 // lazy pointers have references to dyld_stub_binding_helper which need to be ignored
692 if ( (srcAtom
->fSection
->flags() & SECTION_TYPE
) != S_LAZY_SYMBOL_POINTERS
) {
693 uint32_t offsetInSrcAtom
= srcAddr
- srcAtom
->fOffset
;
694 macho_uintptr_t pointerValue
= ENDIAN_SWAP_POINTER(*((macho_uintptr_t
*)fixUpPtr
));
695 if ( reloc
->r_extern() ) {
696 const macho_nlist
* targetSymbol
= &fSymbols
[reloc
->r_symbolnum()];
697 uint8_t type
= targetSymbol
->n_type() & N_TYPE
;
698 if ( type
== N_UNDF
) {
699 const char* targetName
= &fStrings
[targetSymbol
->n_strx()];
700 macho_uintptr_t addend
= pointerValue
;
701 srcAtom
->addByNameReference(offsetInSrcAtom
, Reference::pointer
, targetName
, addend
, 0);
704 dstAddr
= targetSymbol
->n_value();
705 Atom
* dstAtom
= findAtomCoveringOffset(dstAddr
);
706 macho_uintptr_t addend
= pointerValue
;
707 srcAtom
->addReference(offsetInSrcAtom
, Reference::pointer
, *dstAtom
, addend
, 0);
711 Atom
* dstAtom
= findAtomCoveringOffset(pointerValue
);
712 srcAtom
->addReference(offsetInSrcAtom
, Reference::pointer
, *dstAtom
, pointerValue
-dstAtom
->fOffset
, 0);
721 #if defined(ARCH_I386)
722 case GENERIC_RELOC_VANILLA
:
724 srcAddr
= sect
->addr() + reloc
->r_address();
725 src
= findAtomCoveringOffset(srcAddr
);
726 // lazy pointers have references to dyld_stub_binding_helper which need to be ignored
727 if ( (src
->fSection
->flags() & SECTION_TYPE
) != S_LAZY_SYMBOL_POINTERS
) {
728 if ( reloc
->r_length() != 2 )
729 throw "bad vanilla relocation length";
730 Reference::Kind kind
;
731 macho_uintptr_t pointerValue
= ENDIAN_SWAP_POINTER(*((macho_uintptr_t
*)fixUpPtr
));
732 if ( reloc
->r_pcrel() ) {
733 kind
= Reference::x86FixupBranch32
;
734 pointerValue
+= reloc
->r_address() + sizeof(macho_uintptr_t
);
737 kind
= Reference::pointer
;
739 uint32_t offsetInSrcAtom
= srcAddr
- src
->fOffset
;
740 if ( reloc
->r_extern() ) {
741 const macho_nlist
* targetSymbol
= &fSymbols
[reloc
->r_symbolnum()];
742 uint8_t type
= targetSymbol
->n_type() & N_TYPE
;
743 if ( type
== N_UNDF
) {
744 const char* targetName
= &fStrings
[targetSymbol
->n_strx()];
745 macho_uintptr_t addend
= pointerValue
;
746 src
->addByNameReference(offsetInSrcAtom
, kind
, targetName
, addend
, 0);
749 dstAddr
= targetSymbol
->n_value();
750 dst
= findAtomCoveringOffset(dstAddr
);
751 macho_uintptr_t addend
= pointerValue
- dstAddr
;
752 src
->addReference(offsetInSrcAtom
, kind
, *dst
, addend
, 0);
756 dst
= findAtomCoveringOffset(pointerValue
);
757 src
->addReference(offsetInSrcAtom
, kind
, *dst
, 0, 0);
765 printf("unknown relocation type %d\n", reloc
->r_type());
769 const macho_scattered_relocation_info
* sreloc
= (macho_scattered_relocation_info
*)reloc
;
770 srcAddr
= sect
->addr() + sreloc
->r_address();
771 dstAddr
= sreloc
->r_value();
772 fixUpPtr
= (uint32_t*)((char*)(fHeader
) + sect
->offset() + sreloc
->r_address());
773 const macho_scattered_relocation_info
* nextSReloc
= &sreloc
[1];
774 const macho_relocation_info
* nextReloc
= &reloc
[1];
775 // file format allows pair to be scattered or not
776 bool nextRelocIsPair
= false;
777 uint32_t nextRelocAddress
= 0;
778 uint32_t nextRelocValue
= 0;
779 if ( (nextReloc
->r_address() & R_SCATTERED
) == 0 ) {
780 if ( nextReloc
->r_type() == PPC_RELOC_PAIR
) {
781 nextRelocIsPair
= true;
782 nextRelocAddress
= nextReloc
->r_address();
786 if ( nextSReloc
->r_type() == PPC_RELOC_PAIR
) {
787 nextRelocIsPair
= true;
788 nextRelocAddress
= nextSReloc
->r_address();
789 nextRelocValue
= nextSReloc
->r_value();
792 switch (sreloc
->r_type()) {
793 case GENERIC_RELOC_VANILLA
:
795 macho_uintptr_t betterDstAddr
= ENDIAN_SWAP_POINTER(*((macho_uintptr_t
*)fixUpPtr
));
796 //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr);
797 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
798 Atom
* src
= findAtomCoveringOffset(srcAddr
);
799 Atom
* dst
= findAtomCoveringOffset(dstAddr
);
800 src
->addReference(srcAddr
- src
->fOffset
, Reference::pointer
, *dst
, betterDstAddr
- dst
->fOffset
, 0);
803 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
806 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
807 if ( (instruction
& 0x4C000000) == 0x48000000 ) {
808 int32_t displacement
= (instruction
& 0x03FFFFFC);
809 if ( (displacement
& 0x02000000) != 0 )
810 displacement
|= 0xFC000000;
811 srcAddr
= sect
->addr() + sreloc
->r_address();
812 dstAddr
= sreloc
->r_value();
813 src
= findAtomCoveringOffset(srcAddr
);
814 dst
= findAtomCoveringOffset(dstAddr
);
815 this->addCallSiteReference(*src
, srcAddr
- src
->fOffset
, Reference::ppcFixupBranch24
, *dst
, 0, srcAddr
+ displacement
- sreloc
->r_value());
819 case PPC_RELOC_LO16_SECTDIFF
:
821 if ( ! nextRelocIsPair
) {
822 printf("PPC_RELOC_LO16_SECTDIFF missing following PAIR\n");
825 src
= findAtomCoveringOffset(srcAddr
);
826 dst
= findAtomCoveringOffset(dstAddr
);
827 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
828 int16_t lowBits
= (instruction
& 0xFFFF);
829 int32_t displacement
= (nextRelocAddress
<< 16) + (int32_t)lowBits
;
830 if ( (lowBits
& 0x8000) != 0 )
831 displacement
+= 0x10000;
832 uint32_t picBaseOffset
= nextRelocValue
- src
->fOffset
;
833 int64_t dstOffset
= src
->fOffset
+ picBaseOffset
+ displacement
- dst
->fOffset
;
834 src
->addReference(srcAddr
- src
->fOffset
, Reference::ppcFixupPicBaseLow16
, *dst
, dstOffset
, picBaseOffset
);
837 case PPC_RELOC_LO14_SECTDIFF
:
839 if ( ! nextRelocIsPair
) {
840 printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
843 src
= findAtomCoveringOffset(srcAddr
);
844 dst
= findAtomCoveringOffset(dstAddr
);
845 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
846 int16_t lowBits
= (instruction
& 0xFFFC);
847 int32_t displacement
= (nextRelocAddress
<< 16) + (int32_t)lowBits
;
848 if ( (lowBits
& 0x8000) != 0 )
849 displacement
+= 0x10000;
850 uint32_t picBaseOffset
= nextRelocValue
- src
->fOffset
;
851 int64_t dstOffset
= src
->fOffset
+ picBaseOffset
+ displacement
- dst
->fOffset
;
852 src
->addReference(srcAddr
- src
->fOffset
, Reference::ppcFixupPicBaseLow14
, *dst
, dstOffset
, picBaseOffset
);
855 case PPC_RELOC_HA16_SECTDIFF
:
857 if ( ! nextRelocIsPair
) {
858 printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
861 src
= findAtomCoveringOffset(srcAddr
);
862 dst
= findAtomCoveringOffset(dstAddr
);
863 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
864 int16_t lowBits
= (nextRelocAddress
& 0x0000FFFF);
865 int32_t displacement
= ((instruction
& 0x0000FFFF) << 16) + (int32_t)lowBits
;
866 uint32_t picBaseOffset
= nextRelocValue
- src
->fOffset
;
867 int64_t dstOffset
= src
->fOffset
+ picBaseOffset
+ displacement
- dst
->fOffset
;
868 src
->addReference(srcAddr
- src
->fOffset
, Reference::ppcFixupPicBaseHigh16
, *dst
, dstOffset
, picBaseOffset
);
873 if ( ! nextRelocIsPair
) {
874 printf("PPC_RELOC_LO14 missing following PAIR\n");
877 src
= findAtomCoveringOffset(srcAddr
);
878 dst
= findAtomCoveringOffset(dstAddr
);
879 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
880 int16_t lowBits
= (instruction
& 0xFFFC);
881 uint32_t betterDstAddr
= (nextRelocAddress
<< 16) + (int32_t)lowBits
;
882 if ( (lowBits
& 0x8000) != 0 )
883 betterDstAddr
+= 0x10000;
884 src
->addReference(srcAddr
- src
->fOffset
, Reference::ppcFixupAbsLow14
, *dst
, betterDstAddr
- dst
->fOffset
, 0);
889 if ( ! nextRelocIsPair
) {
890 printf("PPC_RELOC_LO16 missing following PAIR\n");
893 src
= findAtomCoveringOffset(srcAddr
);
894 dst
= findAtomCoveringOffset(dstAddr
);
895 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
896 int16_t lowBits
= (instruction
& 0xFFFF);
897 uint32_t betterDstAddr
= (nextRelocAddress
<< 16) + (int32_t)lowBits
;
898 if ( (lowBits
& 0x8000) != 0 )
899 betterDstAddr
+= 0x10000;
900 src
->addReference(srcAddr
- src
->fOffset
, Reference::ppcFixupAbsLow16
, *dst
, betterDstAddr
- dst
->fOffset
, 0);
905 if ( ! nextRelocIsPair
) {
906 printf("PPC_RELOC_HA16 missing following PAIR\n");
909 src
= findAtomCoveringOffset(srcAddr
);
910 dst
= findAtomCoveringOffset(dstAddr
);
911 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
912 int16_t lowBits
= (nextRelocAddress
& 0xFFFF);
913 uint32_t betterDstAddr
= ((instruction
& 0xFFFF) << 16) + (int32_t)lowBits
;
914 src
->addReference(srcAddr
- src
->fOffset
, Reference::ppcFixupAbsHigh16AddLow
, *dst
, betterDstAddr
- dst
->fOffset
, 0);
917 case PPC_RELOC_SECTDIFF
:
918 case PPC_RELOC_LOCAL_SECTDIFF
:
920 const macho_scattered_relocation_info
* nextReloc
= &sreloc
[1];
921 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
922 printf("PPC_RELOC_SECTDIFF missing following pair\n");
925 srcAddr
= sect
->addr() + sreloc
->r_address();
926 uint32_t toAddr
= sreloc
->r_value();
927 uint32_t fromAddr
= nextReloc
->r_value();
928 src
= findAtomCoveringOffset(srcAddr
);
929 Atom
* to
= findAtomCoveringOffset(toAddr
);
930 Atom
* from
= findAtomCoveringOffset(fromAddr
);
931 //macho_intptr_t pointerValue = *(macho_intptr_t*)fixUpPtr;
932 //uint64_t toOffset = to->fOffset;
933 //uint64_t fromOffset = from->fOffset;
934 //int64_t pointerValue64 = pointerValue;
935 //uint64_t addend = pointerValue64 - (toOffset - fromOffset);
936 Reference::Kind kind
= Reference::pointer32Difference
;
937 if ( sreloc
->r_length() == 3 )
938 kind
= Reference::pointer64Difference
;
939 src
->addDifferenceReference(srcAddr
- src
->fOffset
, kind
, *to
, toAddr
- to
->fOffset
, *from
, fromAddr
- from
->fOffset
);
944 case PPC_RELOC_HI16_SECTDIFF
:
945 printf("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF\n");
948 #if defined(ARCH_I386)
949 case GENERIC_RELOC_SECTDIFF
:
950 case GENERIC_RELOC_LOCAL_SECTDIFF
:
952 if ( nextSReloc
->r_type() != GENERIC_RELOC_PAIR
) {
953 printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
956 srcAddr
= sect
->addr() + sreloc
->r_address();
957 uint32_t toAddr
= sreloc
->r_value();
958 uint32_t fromAddr
= nextSReloc
->r_value();
959 src
= findAtomCoveringOffset(srcAddr
);
960 Atom
* to
= findAtomCoveringOffset(toAddr
);
961 Atom
* from
= findAtomCoveringOffset(fromAddr
);
962 Reference::Kind kind
= Reference::pointer32Difference
;
963 if ( sreloc
->r_length() != 2 )
964 throw "bad length for GENERIC_RELOC_SECTDIFF";
965 src
->addDifferenceReference(srcAddr
- src
->fOffset
, kind
, *to
, toAddr
- to
->fOffset
, *from
, fromAddr
- from
->fOffset
);
968 case GENERIC_RELOC_PAIR
:
969 // do nothing, already used via a look ahead
973 printf("unknown scattered relocation type %d\n", sreloc
->r_type());
980 void Reader::addFixUp(uint32_t srcAddr
, uint32_t dstAddr
, Reference::Kind kind
, uint32_t picBaseAddr
)
982 Atom
* src
= findAtomCoveringOffset(srcAddr
);
983 Atom
* dst
= findAtomCoveringOffset(dstAddr
);
984 src
->addReference(srcAddr
- src
->fOffset
, kind
, *dst
, dstAddr
- dst
->fOffset
, picBaseAddr
- src
->fOffset
);
987 Atom
* Reader::findAtomCoveringOffset(uint32_t offset
)
990 // binary search of sorted atoms
991 Atom
** base
= &fAtoms
[0];
992 for (uint32_t n
= fAtoms
.size(); n
> 0; n
/= 2) {
993 Atom
** pivot
= &base
[n
/2];
994 Atom
* pivotAtom
= *pivot
;
995 if ( pivotAtom
->fOffset
<= offset
) {
996 if ( offset
< (pivotAtom
->fOffset
+ pivotAtom
->fSize
) )
999 // move base to symbol after pivot
1009 const uint32_t atomCount
= fAtoms
.size();
1010 for (uint32_t i
=0; i
< atomCount
; ++i
) {
1011 Atom
* atom
= fAtoms
[i
];
1012 if ( (atom
->fOffset
<= offset
) && (offset
< (atom
->fOffset
+ atom
->fSize
)) )
1019 uint32_t Reader::findAtomIndex(const Atom
& atom
)
1021 const Atom
* target
= &atom
;
1022 const uint32_t atomCount
= fAtoms
.size();
1023 for (uint32_t i
=0; i
< atomCount
; ++i
) {
1024 Atom
* anAtom
= fAtoms
[i
];
1025 if ( anAtom
== target
)
1031 static void insertOffset(std::set
<uint32_t>& offsets
, uint32_t value
)
1033 //fprintf(stderr, "cleave point at 0x%08X\n", value);
1034 offsets
.insert(value
);
1037 void Reader::insertOffsetIfNotText(std::set
<uint32_t>& offsets
, uint32_t value
)
1039 const macho_section
* sect
= findSectionCoveringOffset(value
);
1040 if ( (sect
== NULL
) || (strcmp(sect
->segname(),"__TEXT") != 0) || (strncmp(sect
->sectname(),"__text", 6) != 0) ) {
1041 offsets
.insert(value
);
1045 void Reader::insertOffsetIfText(std::set
<uint32_t>& offsets
, uint32_t value
)
1047 const macho_section
* sect
= findSectionCoveringOffset(value
);
1048 if ( (sect
!= NULL
) && (strcmp(sect
->segname(),"__TEXT") == 0) && (strncmp(sect
->sectname(),"__text", 6) == 0) ) {
1049 //fprintf(stderr, "don't cleave point at 0x%08X\n", value);
1050 offsets
.insert(value
);
1054 const macho_section
* Reader::findSectionCoveringOffset(uint32_t offset
)
1056 const macho_section
* const sectionsStart
= (macho_section
*)((char*)fSegment
+ sizeof(macho_segment_command
));
1057 const macho_section
* const sectionsEnd
= §ionsStart
[fSegment
->nsects()];
1058 for (const macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1059 if ( (sect
->addr() <= offset
) && (offset
< (sect
->addr() + sect
->size())) )
1066 void Reader::buildOffsetsSet(const macho_relocation_info
* reloc
, const macho_section
* sect
, std::set
<uint32_t>& cleavePoints
, std::set
<uint32_t>& dontCleavePoints
)
1068 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
1069 uint32_t targetAddr
;
1071 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
1072 uint32_t* fixUpPtr
= (uint32_t*)((char*)(fHeader
) + sect
->offset() + reloc
->r_address());
1073 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
1074 uint32_t instruction
;
1076 switch ( reloc
->r_type() ) {
1077 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
1078 case PPC_RELOC_BR14
:
1079 // do nothing. local branch should not cleave
1081 case PPC_RELOC_BR24
:
1083 if ( ! reloc
->r_extern() ) {
1084 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
1085 if ( (instruction
& 0x4C000000) == 0x48000000 ) {
1086 int32_t displacement
= (instruction
& 0x03FFFFFC);
1087 if ( (displacement
& 0x02000000) != 0 )
1088 displacement
|= 0xFC000000;
1089 //cleavePoints.insert(reloc->r_address() + displacement);
1090 insertOffset(cleavePoints
, sect
->addr() + reloc
->r_address() + displacement
);
1095 case PPC_RELOC_PAIR
:
1096 // skip, processed by a look ahead
1098 case PPC_RELOC_LO16
:
1100 const macho_relocation_info
* nextReloc
= &reloc
[1];
1101 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
1102 printf("PPC_RELOC_LO16 missing following pair\n");
1105 if ( ! reloc
->r_extern() ) {
1106 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
1107 targetAddr
= (nextReloc
->r_address() << 16) | (instruction
& 0x0000FFFF);
1108 //cleavePoints.insert(targetAddr);
1109 insertOffset(cleavePoints
, (targetAddr
));
1113 case PPC_RELOC_LO14
:
1115 const macho_relocation_info
* nextReloc
= &reloc
[1];
1116 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
1117 printf("PPC_RELOC_LO14 missing following pair\n");
1120 if ( ! reloc
->r_extern() ) {
1121 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
1122 targetAddr
= (nextReloc
->r_address() << 16) | (instruction
& 0x0000FFFC);
1123 //cleavePoints.insert(targetAddr);
1124 insertOffset(cleavePoints
, (targetAddr
));
1128 case PPC_RELOC_HI16
:
1130 const macho_relocation_info
* nextReloc
= &reloc
[1];
1131 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
1132 printf("PPC_RELOC_HI16 missing following pair\n");
1135 if ( ! reloc
->r_extern() ) {
1136 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
1137 targetAddr
= ((instruction
& 0x0000FFFF) << 16) | (nextReloc
->r_address() & 0x0000FFFF);
1138 //cleavePoints.insert(targetAddr);
1139 insertOffset(cleavePoints
, targetAddr
);
1143 case PPC_RELOC_HA16
:
1145 const macho_relocation_info
* nextReloc
= &reloc
[1];
1146 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
1147 printf("PPC_RELOC_HA16 missing following pair\n");
1150 if ( ! reloc
->r_extern() ) {
1151 instruction
= OSSwapBigToHostInt32(*fixUpPtr
);
1152 int16_t lowBits
= (nextReloc
->r_address() & 0x0000FFFF);
1153 targetAddr
= ((instruction
& 0x0000FFFF) << 16) + (int32_t)lowBits
;
1154 //cleavePoints.insert(targetAddr);
1155 insertOffset(cleavePoints
, targetAddr
);
1159 case PPC_RELOC_JBSR
:
1163 case GENERIC_RELOC_VANILLA
:
1165 #if defined(ARCH_PPC64)
1166 if ( reloc
->r_length() != 3 )
1167 throw "vanilla pointer relocation found that is not 8-bytes";
1168 #elif defined(ARCH_PPC) || defined(ARCH_I386)
1169 if ( reloc
->r_length() != 2 )
1170 throw "vanilla pointer relocation found that is not 4-bytes";
1172 //fprintf(stderr, "pcrel=%d, len=%d, extern=%d, type=%d\n", reloc->r_pcrel(), reloc->r_length(), reloc->r_extern(), reloc->r_type());
1173 if ( !reloc
->r_extern() ) {
1174 macho_uintptr_t pointerValue
= ENDIAN_SWAP_POINTER(*((macho_uintptr_t
*)fixUpPtr
));
1175 if ( reloc
->r_pcrel() )
1176 pointerValue
+= reloc
->r_address() + sizeof(macho_uintptr_t
);
1177 // a pointer into code does not cleave the code (gcc always pointers to labels)
1178 insertOffsetIfNotText(cleavePoints
, pointerValue
);
1183 printf("unknown relocation type %d\n", reloc
->r_type());
1187 const macho_scattered_relocation_info
* sreloc
= (macho_scattered_relocation_info
*)reloc
;
1188 switch (sreloc
->r_type()) {
1189 case GENERIC_RELOC_VANILLA
:
1190 insertOffset(cleavePoints
, sreloc
->r_value());
1192 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
1193 case PPC_RELOC_BR24
:
1194 insertOffset(cleavePoints
, sreloc
->r_value());
1196 case PPC_RELOC_HA16
:
1197 case PPC_RELOC_HI16
:
1198 case PPC_RELOC_LO16
:
1199 case PPC_RELOC_LO14
:
1200 case PPC_RELOC_LO16_SECTDIFF
:
1201 case PPC_RELOC_LO14_SECTDIFF
:
1202 case PPC_RELOC_HA16_SECTDIFF
:
1203 case PPC_RELOC_HI16_SECTDIFF
:
1204 //cleavePoints.insert(sreloc->r_value());
1205 insertOffset(cleavePoints
, sreloc
->r_value());
1206 insertOffsetIfText(dontCleavePoints
, sreloc
->r_value());
1208 case PPC_RELOC_SECTDIFF
:
1209 case PPC_RELOC_LOCAL_SECTDIFF
:
1210 // these do not cleave up a .o file
1211 // a SECTDIFF in __TEXT probably means a jump table, and should prevent a cleave
1213 const macho_scattered_relocation_info
* nextReloc
= &sreloc
[1];
1214 if ( nextReloc
->r_type() != PPC_RELOC_PAIR
) {
1215 printf("PPC_RELOC_SECTDIFF missing following pair\n");
1218 insertOffsetIfText(dontCleavePoints
, sreloc
->r_value());
1219 insertOffsetIfText(dontCleavePoints
, nextReloc
->r_value());
1222 case PPC_RELOC_PAIR
:
1223 // do nothing, already used via a look ahead
1226 #if defined(ARCH_I386)
1227 case GENERIC_RELOC_SECTDIFF
:
1228 case GENERIC_RELOC_LOCAL_SECTDIFF
:
1229 // these do not cleave up a .o file
1230 // a SECTDIFF in __TEXT probably means a jump table, and should prevent a cleave
1232 const macho_scattered_relocation_info
* nextReloc
= &sreloc
[1];
1233 if ( nextReloc
->r_type() != GENERIC_RELOC_PAIR
) {
1234 printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
1237 insertOffsetIfText(dontCleavePoints
, sreloc
->r_value());
1238 insertOffsetIfText(dontCleavePoints
, nextReloc
->r_value());
1241 case GENERIC_RELOC_PAIR
:
1242 // do nothing, already used via a look ahead
1246 printf("unknown relocation type %d\n", sreloc
->r_type());
1253 Segment
* Reader::makeSegmentFromSection(const macho_section
* sect
)
1255 // make segment object if one does not already exist
1256 const uint32_t segmentCount
= fSegments
.size();
1257 for (uint32_t i
=0; i
< segmentCount
; ++i
) {
1258 Segment
* seg
= fSegments
[i
];
1259 if ( strcmp(sect
->segname(), seg
->getName()) == 0 )
1262 Segment
* seg
= new Segment(sect
);
1263 fSegments
.push_back(seg
);
1267 macho_uintptr_t
Reader::commonsOffset()
1269 return fSegment
->vmsize();
1272 const char* Reader::getPath()
1277 std::vector
<class ObjectFile::Atom
*>& Reader::getAtoms()
1279 return (std::vector
<class ObjectFile::Atom
*>&)(fAtoms
);
1282 std::vector
<class ObjectFile::Atom
*>* Reader::getJustInTimeAtomsFor(const char* name
)
1284 // object files have no just-in-time atoms
1289 std::vector
<ObjectFile::StabsInfo
>* Reader::getStabsDebugInfo()
1291 if ( fNonAtomStabsCount
== 0 )
1294 std::vector
<ObjectFile::StabsInfo
>* stabs
= new std::vector
<ObjectFile::StabsInfo
>();
1295 stabs
->reserve(fNonAtomStabsCount
);
1297 for (uint32_t i
=0; i
< fNonAtomStabsCount
; ++i
) {
1298 const macho_nlist
* sym
= &fSymbols
[fNonAtomStabsStartIndex
+i
];
1299 if ( (sym
->n_type() & N_STAB
) != 0 ) {
1300 ObjectFile::StabsInfo stab
;
1301 stab
.atomOffset
= sym
->n_value();
1302 stab
.string
= &fStrings
[sym
->n_strx()];
1303 stab
.type
= sym
->n_type();
1304 stab
.other
= sym
->n_sect();
1305 stab
.desc
= sym
->n_desc();
1306 // for N_SO n_value is offset of first atom, but our gdb ignores this, so we omit that calculation
1307 if ( stab
.type
== N_SO
)
1308 stab
.atomOffset
= 0;
1309 stabs
->push_back(stab
);
1313 // add any extra N_LSYM's not at start of symbol table
1314 for (std::vector
<uint32_t>::iterator it
=fNonAtomExtras
.begin(); it
!= fNonAtomExtras
.end(); ++it
) {
1315 const macho_nlist
* sym
= &fSymbols
[*it
];
1316 ObjectFile::StabsInfo stab
;
1317 stab
.atomOffset
= sym
->n_value();
1318 stab
.string
= &fStrings
[sym
->n_strx()];
1319 stab
.type
= sym
->n_type();
1320 stab
.other
= sym
->n_sect();
1321 stab
.desc
= sym
->n_desc();
1322 stabs
->push_back(stab
);
1328 void Reader::deadStub(Atom
& target
)
1331 fDeadAtoms
.insert(&target
);
1333 // remove lazy pointer
1334 const int stubNameLen
= strlen(target
.fSynthesizedName
);
1335 char lazyName
[stubNameLen
+8];
1336 strcpy(lazyName
, target
.fSynthesizedName
);
1337 strcpy(&lazyName
[stubNameLen
-5], "$lazy_ptr");
1338 const uint32_t atomCount
= fAtoms
.size();
1339 for (uint32_t i
=1; i
< atomCount
; ++i
) {
1340 Atom
* atom
= fAtoms
[i
];
1341 if ( (atom
->fSynthesizedName
!= NULL
) && (strcmp(atom
->fSynthesizedName
, lazyName
) == 0) ) {
1342 fDeadAtoms
.insert(atom
);
1349 void Reader::addCallSiteReference(Atom
& src
, uint32_t offsetInSrcAtom
, Reference::Kind kind
, Atom
& target
, uint32_t picBaseOffset
, uint32_t offsetInTargetAtom
)
1351 // the compiler some times produces stub to static functions and then calls the stubs
1352 // we need to skip the stub if a static function exists with the same name and remove the stub
1353 if ( target
.isLazyStub() ) {
1354 const macho_section
* section
= target
.fSection
;
1355 uint32_t index
= (target
.fOffset
- section
->addr()) / section
->reserved2();
1356 uint32_t indirectTableIndex
= section
->reserved1() + index
;
1357 uint32_t symbolIndex
= ENDIAN_READ32(fIndirectTable
[indirectTableIndex
]);
1358 if ( (symbolIndex
& INDIRECT_SYMBOL_LOCAL
) == 0 ) {
1359 const macho_nlist
* sym
= &fSymbols
[symbolIndex
];
1360 if ( (sym
->n_value() != 0) && ((sym
->n_type() & N_EXT
) == 0) ) {
1361 Atom
* betterTarget
= this->findAtomCoveringOffset(sym
->n_value());
1362 if ( (betterTarget
!= NULL
) && (betterTarget
->getScope() == ObjectFile::Atom::scopeTranslationUnit
) ) {
1363 // use direct reference to static function
1364 src
.addDirectReference(offsetInSrcAtom
, kind
, *betterTarget
, offsetInTargetAtom
, picBaseOffset
);
1366 // remove stub and lazy pointer
1367 this->deadStub(target
);
1374 // fall through to general case
1375 src
.addReference(offsetInSrcAtom
, kind
, target
, offsetInTargetAtom
, picBaseOffset
);
1379 Atom::Atom(Reader
& owner
, const macho_nlist
* symbol
)
1380 : fOwner(owner
), fSymbol(symbol
), fOffset(0), fSize(0), fSection(NULL
), fSegment(NULL
), fSynthesizedName(NULL
),
1381 fStabsStartIndex(0), fStabsCount(0)
1383 uint8_t type
= symbol
->n_type();
1384 if ( (type
& N_EXT
) == 0 )
1385 fScope
= ObjectFile::Atom::scopeTranslationUnit
;
1386 else if ( (type
& N_PEXT
) != 0 )
1387 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
1389 fScope
= ObjectFile::Atom::scopeGlobal
;
1390 if ( (type
& N_TYPE
) == N_SECT
) {
1392 const macho_section
* sections
= (macho_section
*)((char*)fOwner
.fSegment
+ sizeof(macho_segment_command
));
1393 fSection
= §ions
[fSymbol
->n_sect()-1];
1394 fSegment
= owner
.makeSegmentFromSection(fSection
);
1395 fOffset
= fSymbol
->n_value();
1396 uint8_t type
= fSection
->flags() & SECTION_TYPE
;
1398 case S_LAZY_SYMBOL_POINTERS
:
1399 case S_NON_LAZY_SYMBOL_POINTERS
:
1401 // get target name out of indirect symbol table
1402 uint32_t index
= (fOffset
- fSection
->addr()) / sizeof(macho_uintptr_t
);
1403 index
+= fSection
->reserved1();
1404 uint32_t symbolIndex
= ENDIAN_READ32(fOwner
.fIndirectTable
[index
]);
1405 uint32_t strOffset
= fOwner
.fSymbols
[symbolIndex
].n_strx();
1406 const char* name
= &fOwner
.fStrings
[strOffset
];
1407 Reference
* ref
= this->addByNameReference(0, Reference::pointer
, name
, 0, 0);
1408 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
1410 ref
->setFromTargetName("dyld_stub_binding_helper");
1416 else if ( ((type
& N_TYPE
) == N_UNDF
) && (symbol
->n_value() != 0) ) {
1417 // tentative definition
1418 fSize
= symbol
->n_value();
1419 fSection
= getCommonsSection();
1420 fSegment
= owner
.makeSegmentFromSection(fSection
);
1421 fOffset
= owner
.commonsOffset();
1424 printf("unknown symbol type: %d\n", type
);
1428 Atom::Atom(Reader
& owner
, uint32_t offset
)
1429 : fOwner(owner
), fSymbol(NULL
), fOffset(offset
), fSize(0), fSection(NULL
), fSegment(NULL
), fSynthesizedName(NULL
),
1430 fStabsStartIndex(0), fStabsCount(0)
1432 fSection
= findSectionFromOffset(offset
);
1433 fScope
= ObjectFile::Atom::scopeLinkageUnit
;
1434 fSegment
= owner
.makeSegmentFromSection(fSection
);
1435 uint8_t type
= fSection
->flags() & SECTION_TYPE
;
1437 case S_SYMBOL_STUBS
:
1439 uint32_t index
= (offset
- fSection
->addr()) / fSection
->reserved2();
1440 index
+= fSection
->reserved1();
1441 uint32_t symbolIndex
= ENDIAN_READ32(fOwner
.fIndirectTable
[index
]);
1442 uint32_t strOffset
= fOwner
.fSymbols
[symbolIndex
].n_strx();
1443 const char* name
= &fOwner
.fStrings
[strOffset
];
1444 char* str
= new char[strlen(name
)+8];
1446 strcat(str
, "$stub");
1447 fSynthesizedName
= str
;
1450 case S_LAZY_SYMBOL_POINTERS
:
1451 case S_NON_LAZY_SYMBOL_POINTERS
:
1453 uint32_t index
= (offset
- fSection
->addr()) / sizeof(macho_uintptr_t
);
1454 index
+= fSection
->reserved1();
1455 uint32_t symbolIndex
= ENDIAN_READ32(fOwner
.fIndirectTable
[index
]);
1456 uint32_t strOffset
= fOwner
.fSymbols
[symbolIndex
].n_strx();
1457 const char* name
= &fOwner
.fStrings
[strOffset
];
1458 char* str
= new char[strlen(name
)+16];
1460 if ( type
== S_LAZY_SYMBOL_POINTERS
)
1461 strcat(str
, "$lazy_ptr");
1463 strcat(str
, "$non_lazy_ptr");
1464 fSynthesizedName
= str
;
1465 Reference
* ref
= this->addByNameReference(0, Reference::pointer
, name
, 0, 0);
1466 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
1468 ref
->setFromTargetName("dyld_stub_binding_helper");
1470 const macho_nlist
* sym
= &fOwner
.fSymbols
[symbolIndex
];
1471 if ( (sym
->n_type() & N_TYPE
) == N_UNDF
) {
1472 if ( (sym
->n_desc() & N_WEAK_REF
) != 0 )
1485 macho_section
Atom::fgCommonsSection
;
1488 bool Atom::isLazyStub()
1490 return ( (fSection
->flags() & SECTION_TYPE
) == S_SYMBOL_STUBS
);
1493 const macho_section
* Atom::getCommonsSection() {
1494 if ( strcmp(fgCommonsSection
.sectname(), "__common") != 0 ) {
1495 fgCommonsSection
.set_sectname("__common");
1496 fgCommonsSection
.set_segname("__DATA");
1497 fgCommonsSection
.set_flags(S_ZEROFILL
);
1499 return &fgCommonsSection
;
1502 ObjectFile::Reader
* Atom::getFile() const
1508 const char* Atom::getName() const
1510 if ( fSymbol
!= NULL
)
1511 return &fOwner
.fStrings
[fSymbol
->n_strx()];
1513 return fSynthesizedName
;
1516 const char* Atom::getDisplayName() const
1518 if ( fSymbol
!= NULL
)
1519 return &fOwner
.fStrings
[fSymbol
->n_strx()];
1521 if ( fSynthesizedName
!= NULL
)
1522 return fSynthesizedName
;
1524 static char temp
[32];
1525 sprintf(temp
, "atom #%u", fOwner
.findAtomIndex(*this));
1529 ObjectFile::Atom::Scope
Atom::getScope() const
1534 void Atom::setScope(ObjectFile::Atom::Scope newScope
)
1540 bool Atom::isWeakDefinition() const
1542 if ( isTentativeDefinition() )
1544 if ( fSymbol
!= NULL
)
1545 return ( (fSymbol
->n_desc() & N_WEAK_DEF
) != 0 );
1546 uint8_t type
= fSection
->flags() & SECTION_TYPE
;
1548 case S_SYMBOL_STUBS
:
1549 case S_LAZY_SYMBOL_POINTERS
:
1550 case S_NON_LAZY_SYMBOL_POINTERS
:
1556 bool Atom::isTentativeDefinition() const
1558 return (fSection
== &fgCommonsSection
);
1561 bool Atom::isCoalesableByName() const
1563 uint8_t type
= fSection
->flags() & SECTION_TYPE
;
1565 case S_SYMBOL_STUBS
:
1569 if ( isTentativeDefinition() )
1574 bool Atom::isCoalesableByValue() const
1576 uint8_t type
= fSection
->flags() & SECTION_TYPE
;
1578 case S_CSTRING_LITERALS
:
1579 case S_4BYTE_LITERALS
:
1580 case S_8BYTE_LITERALS
:
1586 bool Atom::isZeroFill() const
1588 return ((fSection
->flags() & SECTION_TYPE
) == S_ZEROFILL
);
1591 bool Atom::dontDeadStrip() const
1593 if ( fSymbol
!= NULL
)
1594 return ( (fSymbol
->n_desc() & N_NO_DEAD_STRIP
) != 0 );
1599 bool Atom::dontStripName() const
1601 if ( fSymbol
!= NULL
)
1602 return ( (fSymbol
->n_desc() & REFERENCED_DYNAMICALLY
) != 0 );
1606 bool Atom::isImportProxy() const
1612 uint64_t Atom::getSize() const
1619 std::vector
<ObjectFile::Reference
*>& Atom::getReferences() const
1621 return (std::vector
<ObjectFile::Reference
*>&)(fReferences
);
1624 bool Atom::mustRemainInSection() const
1629 const char* Atom::getSectionName() const
1631 if ( strlen(fSection
->sectname()) > 15 ) {
1632 static char temp
[18];
1633 strncpy(temp
, fSection
->sectname(), 16);
1637 return fSection
->sectname();
1640 Segment
& Atom::getSegment() const
1645 bool Atom::requiresFollowOnAtom() const
1647 // requires follow-on if built with old compiler and not the last atom
1648 if ( (fOwner
.fHeader
->flags() & MH_SUBSECTIONS_VIA_SYMBOLS
) == 0) {
1649 if ( fOwner
.findAtomIndex(*this) < (fOwner
.fAtoms
.size()-1) )
1655 ObjectFile::Atom
& Atom::getFollowOnAtom() const
1657 uint32_t myIndex
= fOwner
.findAtomIndex(*this);
1658 return *fOwner
.fAtoms
[myIndex
+1];
1661 std::vector
<ObjectFile::StabsInfo
>* Atom::getStabsDebugInfo() const
1663 if ( fStabsCount
== 0 )
1666 std::vector
<ObjectFile::StabsInfo
>* stabs
= new std::vector
<ObjectFile::StabsInfo
>();
1667 stabs
->reserve(fStabsCount
);
1669 for (uint32_t i
=0; i
< fStabsCount
; ++i
) {
1670 const macho_nlist
* sym
= &fOwner
.fSymbols
[fStabsStartIndex
+i
];
1671 if ( (sym
->n_type() & N_STAB
) != 0 ) {
1672 ObjectFile::StabsInfo stab
;
1673 stab
.atomOffset
= sym
->n_value();
1674 stab
.string
= &fOwner
.fStrings
[sym
->n_strx()];
1675 stab
.type
= sym
->n_type();
1676 stab
.other
= sym
->n_sect();
1677 stab
.desc
= sym
->n_desc();
1678 switch ( stab
.type
) {
1680 if ( stab
.other
== 0 )
1682 // end of function N_FUN has size (not address) so should not be adjusted
1691 // all these stab types need their value changed from an absolute address to the atom offset
1692 stab
.atomOffset
-= fOffset
;
1695 stabs
->push_back(stab
);
1702 uint8_t Atom::getAlignment() const
1704 // mach-o file format has no alignment information for atoms - just whole sections
1705 if ( fSection
!= NULL
) {
1706 if ( isTentativeDefinition() ) {
1707 // common symbols align to their size
1708 // that is, a 4-byte common aligns to 4-bytes
1709 // to be safe, odd size commons align to the next power-of-2 size
1710 uint8_t alignment
= (uint8_t)ceil(log2(this->getSize()));
1711 // limit alignment of extremely large commons to 2^15 bytes (8-page)
1712 if ( alignment
< 15 )
1718 // so we assume every atom requires the same alignment as the whole section
1719 return fSection
->align();
1727 void Atom::copyRawContent(uint8_t buffer
[]) const
1731 bzero(buffer
, fSize
);
1733 uint32_t fileOffset
= fSection
->offset() - fSection
->addr() + fOffset
;
1734 memcpy(buffer
, (char*)(fOwner
.fHeader
)+fileOffset
, fSize
);
1738 void Atom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
1740 const uint32_t referencesCount
= fReferences
.size();
1742 // skip copy if no fix-ups
1743 if ( referencesCount
== 0 ) {
1744 uint32_t fileOffset
= fSection
->offset() - fSection
->addr() + fOffset
;
1745 writer
.write(0, (char*)(fOwner
.fHeader
)+fileOffset
, fSize
);
1750 uint8_t buffer
[this->getSize()];
1751 this->copyRawContent(buffer
);
1753 // apply any fix-ups
1754 for (uint32_t i
=0; i
< referencesCount
; ++i
) {
1755 Reference
* ref
= fReferences
[i
];
1756 uint32_t offset
= ref
->getFixUpOffset();
1757 uint32_t* instructionPtr
= (uint32_t*)&buffer
[offset
];
1758 ObjectFile::Atom
& target
= ref
->getTarget();
1759 if ( &target
== NULL
) {
1760 if ( finalLinkedImage
)
1761 throw "target not found";
1765 uint32_t instruction
;
1766 uint32_t newInstruction
;
1767 switch ( ref
->getKind() ) {
1768 case Reference::noFixUp
:
1770 case Reference::pointer
:
1772 //fprintf(stderr, "writeContent: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
1773 if ( target
.isImportProxy() ) {
1774 if ( ref
->isLazyReference() && finalLinkedImage
) {
1775 // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
1776 *((macho_uintptr_t
*)instructionPtr
) = ENDIAN_SWAP_POINTER(ref
->getFromTarget().getAddress());
1779 // external realocation ==> pointer contains addend
1780 *((macho_uintptr_t
*)instructionPtr
) = ENDIAN_SWAP_POINTER(ref
->getTargetOffset());
1784 // internal relocation
1785 if ( finalLinkedImage
|| (strcmp(target
.getSectionName(), "__common") != 0) ) {
1786 // pointer contains target address
1787 //printf("Atom::writeContent() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
1788 *((macho_uintptr_t
*)instructionPtr
) = ENDIAN_SWAP_POINTER(target
.getAddress() + ref
->getTargetOffset());
1791 // pointer contains addend
1792 *((macho_uintptr_t
*)instructionPtr
) = ENDIAN_SWAP_POINTER(ref
->getTargetOffset());
1797 case Reference::ppcFixupBranch24
:
1799 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
1800 int64_t displacement
= (target
.getAddress() + ref
->getTargetOffset() ) - (this->getAddress() + offset
);
1801 if ( !finalLinkedImage
&& target
.isImportProxy() ) {
1802 // doing "ld -r" to an external symbol
1803 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
1804 displacement
-= target
.getAddress();
1807 const int64_t bl_eightMegLimit
= 0x00FFFFFF;
1808 if ( (displacement
> bl_eightMegLimit
) || (displacement
< (-bl_eightMegLimit
)) ) {
1809 //fprintf(stderr, "bl out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
1810 throw "bl out of range";
1813 instruction
= OSReadBigInt32(instructionPtr
, 0);
1814 newInstruction
= (instruction
& 0xFC000003) | ((uint32_t)displacement
& 0x03FFFFFC);
1815 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
1816 OSWriteBigInt32(instructionPtr
, 0, newInstruction
);
1819 case Reference::ppcFixupBranch14
:
1821 case Reference::ppcFixupPicBaseLow16
:
1823 uint64_t targetAddr
= target
.getAddress() + ref
->getTargetOffset();
1824 uint64_t picBaseAddr
= this->getAddress() + ref
->getFromTargetOffset();
1825 int64_t displacement
= targetAddr
- picBaseAddr
;
1826 const int64_t picbase_twoGigLimit
= 0x80000000;
1827 if ( (displacement
> picbase_twoGigLimit
) || (displacement
< (-picbase_twoGigLimit
)) )
1828 throw "32-bit pic-base out of range";
1829 uint16_t instructionLowHalf
= (displacement
& 0xFFFF);
1830 instruction
= OSReadBigInt32(instructionPtr
, 0);
1831 newInstruction
= (instruction
& 0xFFFF0000) | instructionLowHalf
;
1832 OSWriteBigInt32(instructionPtr
, 0, newInstruction
);
1835 case Reference::ppcFixupPicBaseLow14
:
1837 uint64_t targetAddr
= target
.getAddress() + ref
->getTargetOffset();
1838 uint64_t picBaseAddr
= this->getAddress() + ref
->getFromTargetOffset();
1839 int64_t displacement
= targetAddr
- picBaseAddr
;
1840 const int64_t picbase_twoGigLimit
= 0x80000000;
1841 if ( (displacement
> picbase_twoGigLimit
) || (displacement
< (-picbase_twoGigLimit
)) )
1842 throw "32-bit pic-base out of range";
1843 uint16_t instructionLowHalf
= (displacement
& 0xFFFF);
1844 if ( (instructionLowHalf
& 0x3) != 0 )
1845 throw "bad address for lo14 instruction fix-up";
1846 instruction
= OSReadBigInt32(instructionPtr
, 0);
1847 newInstruction
= (instruction
& 0xFFFF0003) | instructionLowHalf
;
1848 OSWriteBigInt32(instructionPtr
, 0, newInstruction
);
1851 case Reference::ppcFixupPicBaseHigh16
:
1853 uint64_t targetAddr
= target
.getAddress() + ref
->getTargetOffset();
1854 uint64_t picBaseAddr
= this->getAddress() + ref
->getFromTargetOffset();
1855 int64_t displacement
= targetAddr
- picBaseAddr
;
1856 const int64_t picbase_twoGigLimit
= 0x80000000;
1857 if ( (displacement
> picbase_twoGigLimit
) || (displacement
< (-picbase_twoGigLimit
)) )
1858 throw "32-bit pic-base out of range";
1859 uint16_t instructionLowHalf
= displacement
>> 16;
1860 if ( (displacement
& 0x00008000) != 0 )
1861 ++instructionLowHalf
;
1862 instruction
= OSReadBigInt32(instructionPtr
, 0);
1863 newInstruction
= (instruction
& 0xFFFF0000) | instructionLowHalf
;
1864 OSWriteBigInt32(instructionPtr
, 0, newInstruction
);
1867 case Reference::ppcFixupAbsLow16
:
1869 int64_t addr
= target
.getAddress() + ref
->getTargetOffset();
1870 if ( !finalLinkedImage
&& target
.isImportProxy() )
1871 addr
-= target
.getAddress() ;
1872 uint16_t instructionLowHalf
= (addr
& 0xFFFF);
1873 instruction
= OSReadBigInt32(instructionPtr
, 0);
1874 newInstruction
= (instruction
& 0xFFFF0000) | instructionLowHalf
;
1875 OSWriteBigInt32(instructionPtr
, 0, newInstruction
);
1878 case Reference::ppcFixupAbsLow14
:
1880 int64_t addr
= target
.getAddress() + ref
->getTargetOffset();
1881 if ( !finalLinkedImage
&& target
.isImportProxy() )
1882 addr
-= target
.getAddress() ;
1883 uint16_t instructionLowHalf
= (addr
& 0xFFFF);
1884 if ( (instructionLowHalf
& 0x3) != 0 )
1885 throw "bad address for lo14 instruction fix-up";
1886 instruction
= OSReadBigInt32(instructionPtr
, 0);
1887 newInstruction
= (instruction
& 0xFFFF0003) | instructionLowHalf
;
1888 OSWriteBigInt32(instructionPtr
, 0, newInstruction
);
1891 case Reference::ppcFixupAbsHigh16
:
1893 int64_t addr
= target
.getAddress() + ref
->getTargetOffset();
1894 if ( !finalLinkedImage
&& target
.isImportProxy() )
1895 addr
-= target
.getAddress() ;
1896 uint16_t hi16
= (addr
>> 16);
1897 instruction
= OSReadBigInt32(instructionPtr
, 0);
1898 newInstruction
= (instruction
& 0xFFFF0000) | hi16
;
1899 OSWriteBigInt32(instructionPtr
, 0, newInstruction
);
1902 case Reference::ppcFixupAbsHigh16AddLow
:
1904 int64_t addr
= target
.getAddress() + ref
->getTargetOffset();
1905 if ( !finalLinkedImage
&& target
.isImportProxy() )
1906 addr
-= target
.getAddress() ;
1907 if ( addr
& 0x00008000 )
1909 instruction
= OSReadBigInt32(instructionPtr
, 0);
1910 newInstruction
= (instruction
& 0xFFFF0000) | (addr
>> 16);
1911 OSWriteBigInt32(instructionPtr
, 0, newInstruction
);
1914 case Reference::pointer32Difference
:
1915 ENDIAN_WRITE32(*instructionPtr
, target
.getAddress() + ref
->getTargetOffset() - (ref
->getFromTarget().getAddress() + ref
->getFromTargetOffset()));
1917 case Reference::pointer64Difference
:
1918 *((uint64_t*)instructionPtr
) = ENDIAN_SWAP64(target
.getAddress() + ref
->getTargetOffset() - (ref
->getFromTarget().getAddress() + ref
->getFromTargetOffset()));
1920 case Reference::x86FixupBranch32
:
1922 int64_t displacement
= target
.getAddress() - (this->getAddress() + offset
);
1923 if ( target
.isImportProxy() ) {
1927 const int64_t bl_twoGigLimit
= 0x7FFFFFFF;
1928 if ( (displacement
> bl_twoGigLimit
) || (displacement
< (-bl_twoGigLimit
)) ) {
1929 //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
1930 throw "call out of range";
1933 OSWriteLittleInt32(instructionPtr
, 0, (int32_t)displacement
);
1940 writer
.write(0, buffer
, getSize());
1945 const macho_section
* Atom::findSectionFromOffset(macho_uintptr_t offset
)
1947 const macho_section
* const sectionsStart
= (const macho_section
*)( (char*)fOwner
.fSegment
+ sizeof(macho_segment_command
) );
1948 const macho_section
* const sectionsEnd
= §ionsStart
[fOwner
.fSegment
->nsects()];
1949 for (const macho_section
* s
= sectionsStart
; s
< sectionsEnd
; ++s
) {
1950 if ( (s
->addr() <= offset
) && (offset
< (s
->addr()+s
->size())) )
1953 throw "section not found";
1956 void Atom::setSize(macho_uintptr_t size
)
1962 void Atom::setFollowOnAtom(Atom
&)
1967 Reference
* Atom::addReference(macho_uintptr_t offsetInSrcAtom
, Reference::Kind kind
, Atom
& target
, uint64_t offsetInTarget
, uint64_t offsetInFromTarget
)
1969 if ( (target
.getScope() != ObjectFile::Atom::scopeTranslationUnit
) && ((target
.fSymbol
!= NULL
) || (target
.fSynthesizedName
!= NULL
)) )
1970 return this->addByNameReference(offsetInSrcAtom
, kind
, target
.getName(), offsetInTarget
, offsetInFromTarget
);
1972 return this->addDirectReference(offsetInSrcAtom
, kind
, target
, offsetInTarget
, offsetInFromTarget
);
1976 Reference
* Atom::addDirectReference(macho_uintptr_t offsetInSrcAtom
, Reference::Kind kind
, Atom
& target
, uint64_t offsetInTarget
, uint64_t offsetInFromTarget
)
1978 Reference
* ref
= new Reference(offsetInSrcAtom
, kind
, target
, offsetInTarget
, offsetInFromTarget
);
1979 // in rare cases, there may already be a by-name reference to the same atom. If so, replace with this direct reference
1980 for (std::vector
<Reference
*>::iterator it
=fReferences
.begin(); it
!= fReferences
.end(); it
++) {
1981 ObjectFile::Reference
* aRef
= *it
;
1982 if ( (aRef
->getFixUpOffset() == offsetInSrcAtom
) && (aRef
->getKind() == kind
) ) {
1988 // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
1989 fReferences
.insert(fReferences
.begin(), ref
);
1993 Reference
* Atom::addByNameReference(macho_uintptr_t offsetInSrcAtom
, Reference::Kind kind
, const char* targetName
, uint64_t offsetInTarget
, uint64_t offsetInFromTarget
)
1995 Reference
* ref
= new Reference(offsetInSrcAtom
, kind
, targetName
, offsetInTarget
, offsetInFromTarget
);
1996 // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
1997 fReferences
.insert(fReferences
.begin(), ref
);
2001 Reference
* Atom::addDifferenceReference(macho_uintptr_t offsetInSrcAtom
, Reference::Kind kind
, Atom
& target
, uint64_t offsetInTarget
, Atom
& fromTarget
, uint64_t offsetInFromTarget
)
2003 Reference
* ref
= new Reference(offsetInSrcAtom
, kind
, target
, offsetInTarget
, fromTarget
, offsetInFromTarget
);
2004 // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
2005 fReferences
.insert(fReferences
.begin(), ref
);
2010 Segment::Segment(const macho_section
* sect
)
2015 const char* Segment::getName() const
2017 return fSection
->segname();
2020 bool Segment::isContentReadable() const
2025 bool Segment::isContentWritable() const
2027 if ( strcmp(fSection
->segname(), "__DATA") == 0 )
2029 if ( strcmp(fSection
->segname(), "__OBJC") == 0 )
2034 bool Segment::isContentExecutable() const
2036 return ( strcmp(fSection
->segname(), "__TEXT") == 0 );
2040 Reference::Reference(macho_uintptr_t fixUpOffset
, Kind kind
, const char* targetName
, uint64_t offsetInTarget
, uint64_t offsetInFromTarget
)
2041 : fTarget(NULL
), fFromTarget(NULL
), fTargetName(targetName
), fFromTargetName(NULL
), fTargetOffset(offsetInTarget
), fFromTargetOffset(offsetInFromTarget
),
2042 fFixUpOffsetInSrc(fixUpOffset
), fKind(kind
), fLazy(false), fWeak(false)
2046 Reference::Reference(macho_uintptr_t fixUpOffset
, Kind kind
, class Atom
& target
, uint64_t offsetInTarget
, uint64_t offsetInFromTarget
)
2047 : fTarget(&target
), fFromTarget(NULL
), fTargetName(NULL
), fFromTargetName(NULL
), fTargetOffset(offsetInTarget
), fFromTargetOffset(offsetInFromTarget
),
2048 fFixUpOffsetInSrc(fixUpOffset
), fKind(kind
), fLazy(false), fWeak(false)
2052 Reference::Reference(macho_uintptr_t fixUpOffset
, Kind kind
, class Atom
& target
, uint64_t offsetInTarget
, class Atom
& fromTarget
, uint64_t offsetInFromTarget
)
2053 : fTarget(&target
), fFromTarget(&fromTarget
), fTargetName(NULL
), fFromTargetName(NULL
), fTargetOffset(offsetInTarget
), fFromTargetOffset(offsetInFromTarget
),
2054 fFixUpOffsetInSrc(fixUpOffset
), fKind(kind
), fLazy(false), fWeak(false)
2056 // assure no direct references to something that might be coalesced
2057 if ( (target
.isWeakDefinition() || target
.isCoalesableByName()) && (target
.getScope() != ObjectFile::Atom::scopeTranslationUnit
) && (target
.getName() != NULL
) ) {
2058 //fprintf(stderr, "change TO direct reference to by-name: from %s to %s in %p\n", fromTarget.getDisplayName(), target.getName(), this);
2059 fTargetName
= target
.getName();
2062 // Note: We should also allow by-name from references, but many other chunks of code assume from targets are always direct//
2063 // if ( (fromTarget.isWeakDefinition() || fromTarget.isCoalesableByName()) && (fromTarget.getScope() != ObjectFile::Atom::scopeTranslationUnit) && (fromTarget.getName() != NULL)) {
2064 // fprintf(stderr, "change FROM direct reference to by-name: from %s to %s in %p\n", fromTarget.getDisplayName(), target.getName(), this);
2065 // fFromTargetName = fromTarget.getName();
2066 // fFromTarget = NULL;
2072 Reference::~Reference()
2076 bool Reference::isUnbound() const
2078 if ( fTarget
== NULL
)
2080 if ( (fFromTargetName
!=NULL
) && (fFromTarget
==NULL
) )
2085 bool Reference::isWeakReference() const
2090 bool Reference::requiresRuntimeFixUp() const
2092 return ( fKind
== Reference::pointer
);
2095 bool Reference::isLazyReference() const
2100 ObjectFile::Reference::Kind
Reference::getKind() const
2105 uint64_t Reference::getFixUpOffset() const
2107 return fFixUpOffsetInSrc
;
2110 const char* Reference::getTargetName() const
2112 if ( fTargetName
!= NULL
)
2114 return fTarget
->getName();
2117 ObjectFile::Atom
& Reference::getTarget() const
2122 void Reference::setTarget(ObjectFile::Atom
& target
)
2128 ObjectFile::Atom
& Reference::getFromTarget() const
2130 return *fFromTarget
;
2133 const char* Reference::getFromTargetName() const
2135 if ( fFromTargetName
!= NULL
)
2136 return fFromTargetName
;
2137 return fFromTarget
->getName();
2140 void Reference::setFromTarget(ObjectFile::Atom
& target
)
2142 fFromTarget
= &target
;
2145 void Reference::setFromTargetName(const char* name
)
2147 fFromTargetName
= name
;
2150 uint64_t Reference::getTargetOffset() const
2152 return fTargetOffset
;
2156 uint64_t Reference::getFromTargetOffset() const
2158 return fFromTargetOffset
;
2161 void Reference::setLazy(bool lazy
)
2166 void Reference::setWeak(bool weak
)
2171 const char* Reference::getDescription() const
2173 static char temp
[256];
2174 if ( fKind
== pointer32Difference
) {
2175 // by-name references have quoted names
2176 bool targetByName
= ( &(this->getTarget()) == NULL
);
2177 bool fromByName
= ( &(this->getFromTarget()) == NULL
);
2178 const char* targetQuotes
= targetByName
? "\"" : "";
2179 const char* fromQuotes
= fromByName
? "\"" : "";
2180 sprintf(temp
, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %lld) - (&%s%s%s + %lld)",
2181 this->getFixUpOffset(), targetQuotes
, this->getTargetName(), targetQuotes
, this->getTargetOffset(),
2182 fromQuotes
, this->getFromTargetName(), fromQuotes
, this->getFromTargetOffset() );
2184 else if ( fKind
== pointer64Difference
) {
2185 // by-name references have quoted names
2186 bool targetByName
= ( &(this->getTarget()) == NULL
);
2187 bool fromByName
= ( &(this->getFromTarget()) == NULL
);
2188 const char* targetQuotes
= targetByName
? "\"" : "";
2189 const char* fromQuotes
= fromByName
? "\"" : "";
2190 sprintf(temp
, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %lld) - (&%s%s%s + %lld)",
2191 this->getFixUpOffset(), targetQuotes
, this->getTargetName(), targetQuotes
, this->getTargetOffset(),
2192 fromQuotes
, this->getFromTargetName(), fromQuotes
, this->getFromTargetOffset() );
2197 sprintf(temp
, "reference to ");
2201 const char* weak
= "";
2204 const char* lazy
= "";
2207 sprintf(temp
, "offset 0x%04llX, %s%spointer to ", this->getFixUpOffset(), weak
, lazy
);
2210 case ppcFixupBranch14
:
2211 case ppcFixupBranch24
:
2212 sprintf(temp
, "offset 0x%04llX, bl pc-rel fixup to ", this->getFixUpOffset());
2214 case ppcFixupPicBaseLow16
:
2215 sprintf(temp
, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
2217 case ppcFixupPicBaseLow14
:
2218 sprintf(temp
, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
2220 case ppcFixupPicBaseHigh16
:
2221 sprintf(temp
, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
2223 case ppcFixupAbsLow16
:
2224 sprintf(temp
, "offset 0x%04llX, low 16 fixup to absolute address of ", this->getFixUpOffset());
2226 case ppcFixupAbsLow14
:
2227 sprintf(temp
, "offset 0x%04llX, low 14 fixup to absolute address of ", this->getFixUpOffset());
2229 case ppcFixupAbsHigh16
:
2230 sprintf(temp
, "offset 0x%04llX, high 16 fixup to absolute address of ", this->getFixUpOffset());
2232 case ppcFixupAbsHigh16AddLow
:
2233 sprintf(temp
, "offset 0x%04llX, high 16 fixup to absolute address of ", this->getFixUpOffset());
2235 case pointer32Difference
:
2236 case pointer64Difference
:
2239 case x86FixupBranch32
:
2240 sprintf(temp
, "offset 0x%04llX, call pc-rel fixup to ", this->getFixUpOffset());
2243 // always quote by-name references
2244 if ( fTargetName
!= NULL
) {
2246 strcat(temp
, fTargetName
);
2249 else if ( fTarget
!= NULL
) {
2250 strcat(temp
, fTarget
->getDisplayName());
2253 strcat(temp
, "NULL target");
2255 if ( fTargetOffset
!= 0 )
2256 sprintf(&temp
[strlen(temp
)], " plus 0x%08llX", this->getTargetOffset());
2257 if ( (fKind
==pointer
) && fLazy
) {
2258 strcat(temp
, " initially bound to \"");
2259 strcat(temp
, this->getFromTargetName());