]> git.saurik.com Git - apple/ld64.git/blob - src/Readers/ObjectFileMachO.cpp
5736d00552955ed05a3ecc66bf5557f3bd82ce68
[apple/ld64.git] / src / Readers / ObjectFileMachO.cpp
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- */
24
25
26 namespace ObjectFileMachO {
27
28 class Reference : public ObjectFile::Reference
29 {
30 public:
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);
34 virtual ~Reference();
35
36
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;
53
54 void setLazy(bool);
55 void setWeak(bool);
56 private:
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;
64 Kind fKind;
65 bool fLazy;
66 bool fWeak;
67 };
68
69
70
71 class Reader : public ObjectFile::Reader
72 {
73 public:
74 Reader(const char* path);
75 Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options);
76 virtual ~Reader();
77
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
82
83
84 private:
85 friend class 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);
99
100 const char* fPath;
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;
114 };
115
116 class Segment : public ObjectFile::Segment
117 {
118 public:
119 virtual const char* getName() const;
120 virtual bool isContentReadable() const;
121 virtual bool isContentWritable() const;
122 virtual bool isContentExecutable() const;
123 protected:
124 Segment(const macho_section*);
125 friend class Reader;
126 private:
127 const macho_section* fSection;
128 };
129
130 class Atom : public ObjectFile::Atom
131 {
132 public:
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) { }
159
160 bool isLazyStub();
161
162 protected:
163 friend class Reader;
164 Atom(Reader&, const macho_nlist*);
165 Atom(Reader&, uint32_t offset);
166 virtual ~Atom();
167
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);
177
178 Reader& fOwner;
179 const macho_nlist* fSymbol;
180 macho_uintptr_t fOffset;
181 macho_uintptr_t fSize;
182 const macho_section* fSection;
183 Segment* fSegment;
184 const char* fSynthesizedName;
185 std::vector<class Reference*> fReferences;
186 ObjectFile::Atom::Scope fScope;
187 uint32_t fStabsStartIndex;
188 uint32_t fStabsCount;
189
190 static macho_section fgCommonsSection; // for us by tentative definitions
191 };
192
193
194 Reader* MakeReader(const macho_header* mh, const char* path, const ObjectFile::ReaderOptions& options)
195 {
196 return new Reader(mh, path, options);
197 }
198
199
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)
202 {
203 init(header, path);
204 }
205
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)
209 {
210 struct stat stat_buf;
211
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);
215 ::close(fd);
216 if ( ((macho_header*)p)->magic() == MH_MAGIC ) {
217 init((macho_header*)p, path);
218 return;
219 }
220 throw "add fat handling";
221 }
222
223
224 Reader::~Reader()
225 {
226 }
227
228
229 bool Atom::atomCompare(const Atom* lhs, const Atom* rhs)
230 {
231 return lhs->fOffset < rhs->fOffset;
232 }
233
234
235
236 void Reader::init(const macho_header* header, const char* path)
237 {
238 // sanity check
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";
248 #endif
249
250 // cache intersting pointers
251 fPath = strdup(path);
252 fHeader = header;
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()) {
258 case LC_SYMTAB:
259 {
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();
264 }
265 break;
266 case LC_DYSYMTAB:
267 {
268 const macho_dysymtab_command* dsymtab = (struct macho_dysymtab_command*)cmd;
269 fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
270 }
271 break;
272 default:
273 if ( cmd->cmd() == macho_segment_command::command ) {
274 fSegment= (macho_segment_command*)cmd;
275 }
276 break;
277 }
278 cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
279 }
280
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);
292 }
293 }
294 }
295
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 = &sectionsStart[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);
306 }
307 }
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);
312 switch ( type ) {
313 case S_SYMBOL_STUBS:
314 {
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);
323 }
324 }
325 }
326 }
327 break;
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);
333 }
334 break;
335 }
336 // also make sure each section break is a cleave point
337 if ( sect->size() != 0 )
338 cleavePoints.insert(sect->addr());
339 }
340
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));
347 }
348
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);
353
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);
362 else
363 lastAtom->setSize(lastAtom->fSection->addr() + lastAtom->fSection->size() - lastAtom->fOffset);
364 }
365 if ( dontDeadStrip )
366 lastAtom->setFollowOnAtom(*thisAtom);
367 lastAtom = thisAtom;
368 }
369 lastAtom = fAtoms[atomCount-1];
370 if ( lastAtom->getSize() == 0 )
371 lastAtom->setSize(lastAtom->fSection->addr() + lastAtom->fSection->size() - lastAtom->fOffset);
372
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]);
379 }
380 }
381
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);
386 }
387
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 ) {
392 fAtoms.erase(it);
393 break;
394 }
395 }
396 }
397 }
398
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;
405 Atom* atom = NULL;
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;
414 switch (state) {
415 case start:
416 if ( (type == N_SLINE) || (type == N_SOL) ) {
417 possibleStart = symbolIndex;
418 state = foundFirst;
419 }
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;
427 }
428 else {
429 fprintf(stderr, "can't find atom for stabs 0x%02X at %08X in %s\n", type, targetAddr, path);
430 atom = NULL;
431 }
432 state = inBeginEnd;
433 }
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;
442 }
443 else {
444 fprintf(stderr, "can't find atom for stabs 0x%02X at %08X in %s\n", type, targetAddr, path);
445 atom = NULL;
446 }
447 }
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, ':');
453 bool found = false;
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;
464 found = true;
465 break;
466 }
467 }
468 }
469 if ( !found ) {
470 fprintf(stderr, "can't find atom for N_GSYM stabs %s in %s\n", symString, path);
471 atom = NULL;
472 }
473 }
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);
478 }
479 }
480 break;
481 case inBeginEnd:
482 if ( type == N_ENSYM ) {
483 state = start;
484 if ( atom != NULL )
485 atom->fStabsCount = symbolIndex - atom->fStabsStartIndex + 1;
486 }
487 break;
488 case foundFirst:
489 if ( (type == N_FUN) && (sym->n_sect() != 0) ) {
490 state = inFunction;
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);
495 atom = NULL;
496 }
497 else {
498 atom->fStabsStartIndex = possibleStart;
499 if ( fNonAtomStabsCount == 0 )
500 fNonAtomStabsCount = possibleStart - fNonAtomStabsStartIndex;
501 }
502 }
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);
505 state = start;
506 }
507 break;
508 case inFunction:
509 if ( (type == N_FUN) && (sym->n_sect() == 0) ) {
510 state = start;
511 if ( atom != NULL )
512 atom->fStabsCount = symbolIndex - atom->fStabsStartIndex + 1;
513 }
514 break;
515 }
516 }
517 }
518
519 }
520 }
521
522
523 void Reader::addRelocReference(const macho_section* sect, const macho_relocation_info* reloc)
524 {
525 uint32_t srcAddr;
526 uint32_t dstAddr;
527 Atom* src;
528 Atom* dst;
529 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
530 uint32_t instruction;
531 #endif
532 uint32_t* fixUpPtr;
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];
537 #endif
538 switch ( reloc->r_type() ) {
539 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
540 case PPC_RELOC_BR24:
541 {
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);
553 }
554 else {
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);
565 }
566 }
567 }
568 break;
569 case PPC_RELOC_BR14:
570 {
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);
577 }
578 else {
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);
588 }
589 }
590 break;
591 case PPC_RELOC_PAIR:
592 // skip, processed by a previous look ahead
593 break;
594 case PPC_RELOC_LO16:
595 {
596 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
597 printf("PPC_RELOC_LO16 missing following pair\n");
598 break;
599 }
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);
608 }
609 else {
610 instruction = OSSwapBigToHostInt32(*fixUpPtr);
611 int16_t lowBits = (instruction & 0xFFFF);
612 dstAddr = (nextReloc->r_address() << 16) + (int32_t)lowBits;
613 if ( (lowBits & 0x8000) != 0 )
614 dstAddr += 0x10000;
615 addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsLow16, 0);
616 }
617 }
618 break;
619 case PPC_RELOC_LO14:
620 {
621 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
622 printf("PPC_RELOC_LO14 missing following pair\n");
623 break;
624 }
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);
633 }
634 else {
635 instruction = OSSwapBigToHostInt32(*fixUpPtr);
636 dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC);
637 addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsLow14, 0);
638 }
639 }
640 break;
641 case PPC_RELOC_HI16:
642 {
643 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
644 printf("PPC_RELOC_HI16 missing following pair\n");
645 break;
646 }
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);
655 }
656 else {
657 instruction = OSSwapBigToHostInt32(*fixUpPtr);
658 dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
659 addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsHigh16, 0);
660 }
661 }
662 break;
663 case PPC_RELOC_HA16:
664 {
665 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
666 printf("PPC_RELOC_HA16 missing following pair\n");
667 break;
668 }
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);
678 }
679 else {
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);
684 }
685 }
686 break;
687 case GENERIC_RELOC_VANILLA:
688 {
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);
702 }
703 else {
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);
708 }
709 }
710 else {
711 Atom* dstAtom = findAtomCoveringOffset(pointerValue);
712 srcAtom->addReference(offsetInSrcAtom, Reference::pointer, *dstAtom, pointerValue-dstAtom->fOffset, 0);
713 }
714 }
715 }
716 break;
717 case PPC_RELOC_JBSR:
718 // ignore for now
719 break;
720 #endif
721 #if defined(ARCH_I386)
722 case GENERIC_RELOC_VANILLA:
723 {
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);
735 }
736 else {
737 kind = Reference::pointer;
738 }
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);
747 }
748 else {
749 dstAddr = targetSymbol->n_value();
750 dst = findAtomCoveringOffset(dstAddr);
751 macho_uintptr_t addend = pointerValue - dstAddr;
752 src->addReference(offsetInSrcAtom, kind, *dst, addend, 0);
753 }
754 }
755 else {
756 dst = findAtomCoveringOffset(pointerValue);
757 src->addReference(offsetInSrcAtom, kind, *dst, 0, 0);
758 }
759 }
760 }
761 break;
762 #endif
763
764 default:
765 printf("unknown relocation type %d\n", reloc->r_type());
766 }
767 }
768 else {
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();
783 }
784 }
785 else {
786 if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
787 nextRelocIsPair = true;
788 nextRelocAddress = nextSReloc->r_address();
789 nextRelocValue = nextSReloc->r_value();
790 }
791 }
792 switch (sreloc->r_type()) {
793 case GENERIC_RELOC_VANILLA:
794 {
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);
801 }
802 break;
803 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
804 case PPC_RELOC_BR24:
805 {
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());
816 }
817 }
818 break;
819 case PPC_RELOC_LO16_SECTDIFF:
820 {
821 if ( ! nextRelocIsPair) {
822 printf("PPC_RELOC_LO16_SECTDIFF missing following PAIR\n");
823 break;
824 }
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);
835 }
836 break;
837 case PPC_RELOC_LO14_SECTDIFF:
838 {
839 if ( ! nextRelocIsPair) {
840 printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
841 break;
842 }
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);
853 }
854 break;
855 case PPC_RELOC_HA16_SECTDIFF:
856 {
857 if ( ! nextRelocIsPair) {
858 printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
859 break;
860 }
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);
869 }
870 break;
871 case PPC_RELOC_LO14:
872 {
873 if ( ! nextRelocIsPair) {
874 printf("PPC_RELOC_LO14 missing following PAIR\n");
875 break;
876 }
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);
885 }
886 break;
887 case PPC_RELOC_LO16:
888 {
889 if ( ! nextRelocIsPair) {
890 printf("PPC_RELOC_LO16 missing following PAIR\n");
891 break;
892 }
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);
901 }
902 break;
903 case PPC_RELOC_HA16:
904 {
905 if ( ! nextRelocIsPair) {
906 printf("PPC_RELOC_HA16 missing following PAIR\n");
907 break;
908 }
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);
915 }
916 break;
917 case PPC_RELOC_SECTDIFF:
918 case PPC_RELOC_LOCAL_SECTDIFF:
919 {
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");
923 break;
924 }
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);
940 }
941 break;
942 case PPC_RELOC_PAIR:
943 break;
944 case PPC_RELOC_HI16_SECTDIFF:
945 printf("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF\n");
946 break;
947 #endif
948 #if defined(ARCH_I386)
949 case GENERIC_RELOC_SECTDIFF:
950 case GENERIC_RELOC_LOCAL_SECTDIFF:
951 {
952 if ( nextSReloc->r_type() != GENERIC_RELOC_PAIR ) {
953 printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
954 break;
955 }
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);
966 }
967 break;
968 case GENERIC_RELOC_PAIR:
969 // do nothing, already used via a look ahead
970 break;
971 #endif
972 default:
973 printf("unknown scattered relocation type %d\n", sreloc->r_type());
974 }
975
976 }
977 }
978
979
980 void Reader::addFixUp(uint32_t srcAddr, uint32_t dstAddr, Reference::Kind kind, uint32_t picBaseAddr)
981 {
982 Atom* src = findAtomCoveringOffset(srcAddr);
983 Atom* dst = findAtomCoveringOffset(dstAddr);
984 src->addReference(srcAddr - src->fOffset, kind, *dst, dstAddr - dst->fOffset, picBaseAddr - src->fOffset);
985 }
986
987 Atom* Reader::findAtomCoveringOffset(uint32_t offset)
988 {
989 #if 1
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) )
997 return pivotAtom;
998 // key > pivot
999 // move base to symbol after pivot
1000 base = &pivot[1];
1001 --n;
1002 }
1003 else {
1004 // key < pivot
1005 // keep same base
1006 }
1007 }
1008 #else
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)) )
1013 return atom;
1014 }
1015 #endif
1016 return NULL;
1017 }
1018
1019 uint32_t Reader::findAtomIndex(const Atom& atom)
1020 {
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 )
1026 return i;
1027 }
1028 return 0xffffffff;
1029 }
1030
1031 static void insertOffset(std::set<uint32_t>& offsets, uint32_t value)
1032 {
1033 //fprintf(stderr, "cleave point at 0x%08X\n", value);
1034 offsets.insert(value);
1035 }
1036
1037 void Reader::insertOffsetIfNotText(std::set<uint32_t>& offsets, uint32_t value)
1038 {
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);
1042 }
1043 }
1044
1045 void Reader::insertOffsetIfText(std::set<uint32_t>& offsets, uint32_t value)
1046 {
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);
1051 }
1052 }
1053
1054 const macho_section* Reader::findSectionCoveringOffset(uint32_t offset)
1055 {
1056 const macho_section* const sectionsStart = (macho_section*)((char*)fSegment + sizeof(macho_segment_command));
1057 const macho_section* const sectionsEnd = &sectionsStart[fSegment->nsects()];
1058 for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1059 if ( (sect->addr() <= offset) && (offset < (sect->addr() + sect->size())) )
1060 return sect;
1061 }
1062 return NULL;
1063 }
1064
1065
1066 void Reader::buildOffsetsSet(const macho_relocation_info* reloc, const macho_section* sect, std::set<uint32_t>& cleavePoints, std::set<uint32_t>& dontCleavePoints)
1067 {
1068 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
1069 uint32_t targetAddr;
1070 #endif
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;
1075 #endif
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
1080 break;
1081 case PPC_RELOC_BR24:
1082 {
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);
1091 }
1092 }
1093 }
1094 break;
1095 case PPC_RELOC_PAIR:
1096 // skip, processed by a look ahead
1097 break;
1098 case PPC_RELOC_LO16:
1099 {
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");
1103 break;
1104 }
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));
1110 }
1111 }
1112 break;
1113 case PPC_RELOC_LO14:
1114 {
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");
1118 break;
1119 }
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));
1125 }
1126 }
1127 break;
1128 case PPC_RELOC_HI16:
1129 {
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");
1133 break;
1134 }
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);
1140 }
1141 }
1142 break;
1143 case PPC_RELOC_HA16:
1144 {
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");
1148 break;
1149 }
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);
1156 }
1157 }
1158 break;
1159 case PPC_RELOC_JBSR:
1160 // ignore for now
1161 break;
1162 #endif
1163 case GENERIC_RELOC_VANILLA:
1164 {
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";
1171 #endif
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);
1179 }
1180 }
1181 break;
1182 default:
1183 printf("unknown relocation type %d\n", reloc->r_type());
1184 }
1185 }
1186 else {
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());
1191 break;
1192 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
1193 case PPC_RELOC_BR24:
1194 insertOffset(cleavePoints, sreloc->r_value());
1195 break;
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());
1207 break;
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
1212 {
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");
1216 break;
1217 }
1218 insertOffsetIfText(dontCleavePoints, sreloc->r_value());
1219 insertOffsetIfText(dontCleavePoints, nextReloc->r_value());
1220 }
1221 break;
1222 case PPC_RELOC_PAIR:
1223 // do nothing, already used via a look ahead
1224 break;
1225 #endif
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
1231 {
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");
1235 break;
1236 }
1237 insertOffsetIfText(dontCleavePoints, sreloc->r_value());
1238 insertOffsetIfText(dontCleavePoints, nextReloc->r_value());
1239 }
1240 break;
1241 case GENERIC_RELOC_PAIR:
1242 // do nothing, already used via a look ahead
1243 break;
1244 #endif
1245 default:
1246 printf("unknown relocation type %d\n", sreloc->r_type());
1247 }
1248
1249 }
1250 }
1251
1252
1253 Segment* Reader::makeSegmentFromSection(const macho_section* sect)
1254 {
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 )
1260 return seg;
1261 }
1262 Segment* seg = new Segment(sect);
1263 fSegments.push_back(seg);
1264 return seg;
1265 }
1266
1267 macho_uintptr_t Reader::commonsOffset()
1268 {
1269 return fSegment->vmsize();
1270 }
1271
1272 const char* Reader::getPath()
1273 {
1274 return fPath;
1275 }
1276
1277 std::vector<class ObjectFile::Atom*>& Reader::getAtoms()
1278 {
1279 return (std::vector<class ObjectFile::Atom*>&)(fAtoms);
1280 }
1281
1282 std::vector<class ObjectFile::Atom*>* Reader::getJustInTimeAtomsFor(const char* name)
1283 {
1284 // object files have no just-in-time atoms
1285 return NULL;
1286 }
1287
1288
1289 std::vector<ObjectFile::StabsInfo>* Reader::getStabsDebugInfo()
1290 {
1291 if ( fNonAtomStabsCount == 0 )
1292 return NULL;
1293
1294 std::vector<ObjectFile::StabsInfo>* stabs = new std::vector<ObjectFile::StabsInfo>();
1295 stabs->reserve(fNonAtomStabsCount);
1296
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);
1310 }
1311 }
1312
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);
1323 }
1324
1325 return stabs;
1326 }
1327
1328 void Reader::deadStub(Atom& target)
1329 {
1330 // remove stub
1331 fDeadAtoms.insert(&target);
1332
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);
1343 break;
1344 }
1345 }
1346 }
1347
1348
1349 void Reader::addCallSiteReference(Atom& src, uint32_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint32_t picBaseOffset, uint32_t offsetInTargetAtom)
1350 {
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);
1365
1366 // remove stub and lazy pointer
1367 this->deadStub(target);
1368 return;
1369 }
1370 }
1371 }
1372 }
1373
1374 // fall through to general case
1375 src.addReference(offsetInSrcAtom, kind, target, offsetInTargetAtom, picBaseOffset);
1376 }
1377
1378
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)
1382 {
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;
1388 else
1389 fScope = ObjectFile::Atom::scopeGlobal;
1390 if ( (type & N_TYPE) == N_SECT ) {
1391 // real definition
1392 const macho_section* sections = (macho_section*)((char*)fOwner.fSegment + sizeof(macho_segment_command));
1393 fSection = &sections[fSymbol->n_sect()-1];
1394 fSegment = owner.makeSegmentFromSection(fSection);
1395 fOffset = fSymbol->n_value();
1396 uint8_t type = fSection->flags() & SECTION_TYPE;
1397 switch ( type ) {
1398 case S_LAZY_SYMBOL_POINTERS:
1399 case S_NON_LAZY_SYMBOL_POINTERS:
1400 {
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 ) {
1409 ref->setLazy(true);
1410 ref->setFromTargetName("dyld_stub_binding_helper");
1411 }
1412 }
1413 break;
1414 }
1415 }
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();
1422 }
1423 else {
1424 printf("unknown symbol type: %d\n", type);
1425 }
1426 }
1427
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)
1431 {
1432 fSection = findSectionFromOffset(offset);
1433 fScope = ObjectFile::Atom::scopeLinkageUnit;
1434 fSegment = owner.makeSegmentFromSection(fSection);
1435 uint8_t type = fSection->flags() & SECTION_TYPE;
1436 switch ( type ) {
1437 case S_SYMBOL_STUBS:
1438 {
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];
1445 strcpy(str, name);
1446 strcat(str, "$stub");
1447 fSynthesizedName = str;
1448 }
1449 break;
1450 case S_LAZY_SYMBOL_POINTERS:
1451 case S_NON_LAZY_SYMBOL_POINTERS:
1452 {
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];
1459 strcpy(str, name);
1460 if ( type == S_LAZY_SYMBOL_POINTERS )
1461 strcat(str, "$lazy_ptr");
1462 else
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 ) {
1467 ref->setLazy(true);
1468 ref->setFromTargetName("dyld_stub_binding_helper");
1469 }
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 )
1473 ref->setWeak(true);
1474 }
1475 }
1476 break;
1477 }
1478 }
1479
1480
1481 Atom::~Atom()
1482 {
1483 }
1484
1485 macho_section Atom::fgCommonsSection;
1486
1487
1488 bool Atom::isLazyStub()
1489 {
1490 return ( (fSection->flags() & SECTION_TYPE) == S_SYMBOL_STUBS);
1491 }
1492
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);
1498 }
1499 return &fgCommonsSection;
1500 }
1501
1502 ObjectFile::Reader* Atom::getFile() const
1503 {
1504 return &fOwner;
1505 }
1506
1507
1508 const char* Atom::getName() const
1509 {
1510 if ( fSymbol != NULL )
1511 return &fOwner.fStrings[fSymbol->n_strx()];
1512 else
1513 return fSynthesizedName;
1514 }
1515
1516 const char* Atom::getDisplayName() const
1517 {
1518 if ( fSymbol != NULL )
1519 return &fOwner.fStrings[fSymbol->n_strx()];
1520
1521 if ( fSynthesizedName != NULL )
1522 return fSynthesizedName;
1523
1524 static char temp[32];
1525 sprintf(temp, "atom #%u", fOwner.findAtomIndex(*this));
1526 return temp;
1527 }
1528
1529 ObjectFile::Atom::Scope Atom::getScope() const
1530 {
1531 return fScope;
1532 }
1533
1534 void Atom::setScope(ObjectFile::Atom::Scope newScope)
1535 {
1536 fScope = newScope;
1537 }
1538
1539
1540 bool Atom::isWeakDefinition() const
1541 {
1542 if ( isTentativeDefinition() )
1543 return true;
1544 if ( fSymbol != NULL )
1545 return ( (fSymbol->n_desc() & N_WEAK_DEF) != 0 );
1546 uint8_t type = fSection->flags() & SECTION_TYPE;
1547 switch ( type ) {
1548 case S_SYMBOL_STUBS:
1549 case S_LAZY_SYMBOL_POINTERS:
1550 case S_NON_LAZY_SYMBOL_POINTERS:
1551 return true;
1552 }
1553 return false;
1554 }
1555
1556 bool Atom::isTentativeDefinition() const
1557 {
1558 return (fSection == &fgCommonsSection);
1559 }
1560
1561 bool Atom::isCoalesableByName() const
1562 {
1563 uint8_t type = fSection->flags() & SECTION_TYPE;
1564 switch ( type ) {
1565 case S_SYMBOL_STUBS:
1566 case S_COALESCED:
1567 return true;
1568 };
1569 if ( isTentativeDefinition() )
1570 return true;
1571 return false;
1572 }
1573
1574 bool Atom::isCoalesableByValue() const
1575 {
1576 uint8_t type = fSection->flags() & SECTION_TYPE;
1577 switch ( type ) {
1578 case S_CSTRING_LITERALS:
1579 case S_4BYTE_LITERALS:
1580 case S_8BYTE_LITERALS:
1581 return true;
1582 };
1583 return false;
1584 }
1585
1586 bool Atom::isZeroFill() const
1587 {
1588 return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL);
1589 }
1590
1591 bool Atom::dontDeadStrip() const
1592 {
1593 if ( fSymbol != NULL )
1594 return ( (fSymbol->n_desc() & N_NO_DEAD_STRIP) != 0 );
1595 return false;
1596 }
1597
1598
1599 bool Atom::dontStripName() const
1600 {
1601 if ( fSymbol != NULL )
1602 return ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0 );
1603 return false;
1604 }
1605
1606 bool Atom::isImportProxy() const
1607 {
1608 return false;
1609 }
1610
1611
1612 uint64_t Atom::getSize() const
1613 {
1614 //return fOffset;
1615 return fSize;
1616 }
1617
1618
1619 std::vector<ObjectFile::Reference*>& Atom::getReferences() const
1620 {
1621 return (std::vector<ObjectFile::Reference*>&)(fReferences);
1622 }
1623
1624 bool Atom::mustRemainInSection() const
1625 {
1626 return true;
1627 }
1628
1629 const char* Atom::getSectionName() const
1630 {
1631 if ( strlen(fSection->sectname()) > 15 ) {
1632 static char temp[18];
1633 strncpy(temp, fSection->sectname(), 16);
1634 temp[17] = '\0';
1635 return temp;
1636 }
1637 return fSection->sectname();
1638 }
1639
1640 Segment& Atom::getSegment() const
1641 {
1642 return *fSegment;
1643 }
1644
1645 bool Atom::requiresFollowOnAtom() const
1646 {
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) )
1650 return true;
1651 }
1652 return false;
1653 }
1654
1655 ObjectFile::Atom& Atom::getFollowOnAtom() const
1656 {
1657 uint32_t myIndex = fOwner.findAtomIndex(*this);
1658 return *fOwner.fAtoms[myIndex+1];
1659 }
1660
1661 std::vector<ObjectFile::StabsInfo>* Atom::getStabsDebugInfo() const
1662 {
1663 if ( fStabsCount == 0 )
1664 return NULL;
1665
1666 std::vector<ObjectFile::StabsInfo>* stabs = new std::vector<ObjectFile::StabsInfo>();
1667 stabs->reserve(fStabsCount);
1668
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 ) {
1679 case N_FUN:
1680 if ( stab.other == 0 )
1681 break;
1682 // end of function N_FUN has size (not address) so should not be adjusted
1683 // fall through
1684 case N_BNSYM:
1685 case N_ENSYM:
1686 case N_LBRAC:
1687 case N_RBRAC:
1688 case N_SLINE:
1689 case N_STSYM:
1690 case N_LCSYM:
1691 // all these stab types need their value changed from an absolute address to the atom offset
1692 stab.atomOffset -= fOffset;
1693 break;
1694 }
1695 stabs->push_back(stab);
1696 }
1697 }
1698
1699 return stabs;
1700 }
1701
1702 uint8_t Atom::getAlignment() const
1703 {
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 )
1713 return alignment;
1714 else
1715 return 15;
1716 }
1717 else {
1718 // so we assume every atom requires the same alignment as the whole section
1719 return fSection->align();
1720 }
1721 }
1722 else {
1723 return 2;
1724 }
1725 }
1726
1727 void Atom::copyRawContent(uint8_t buffer[]) const
1728 {
1729 // copy base bytes
1730 if ( isZeroFill() )
1731 bzero(buffer, fSize);
1732 else {
1733 uint32_t fileOffset = fSection->offset() - fSection->addr() + fOffset;
1734 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
1735 }
1736 }
1737
1738 void Atom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
1739 {
1740 const uint32_t referencesCount = fReferences.size();
1741
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);
1746 return;
1747 }
1748
1749 // copy base bytes
1750 uint8_t buffer[this->getSize()];
1751 this->copyRawContent(buffer);
1752
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";
1762 else
1763 continue;
1764 }
1765 uint32_t instruction;
1766 uint32_t newInstruction;
1767 switch ( ref->getKind() ) {
1768 case Reference::noFixUp:
1769 break;
1770 case Reference::pointer:
1771 {
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());
1777 }
1778 else {
1779 // external realocation ==> pointer contains addend
1780 *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getTargetOffset());
1781 }
1782 }
1783 else {
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());
1789 }
1790 else {
1791 // pointer contains addend
1792 *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getTargetOffset());
1793 }
1794 }
1795 }
1796 break;
1797 case Reference::ppcFixupBranch24:
1798 {
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();
1805 }
1806 else {
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";
1811 }
1812 }
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);
1817 }
1818 break;
1819 case Reference::ppcFixupBranch14:
1820 break;
1821 case Reference::ppcFixupPicBaseLow16:
1822 {
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);
1833 }
1834 break;
1835 case Reference::ppcFixupPicBaseLow14:
1836 {
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);
1849 }
1850 break;
1851 case Reference::ppcFixupPicBaseHigh16:
1852 {
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);
1865 }
1866 break;
1867 case Reference::ppcFixupAbsLow16:
1868 {
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);
1876 }
1877 break;
1878 case Reference::ppcFixupAbsLow14:
1879 {
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);
1889 }
1890 break;
1891 case Reference::ppcFixupAbsHigh16:
1892 {
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);
1900 }
1901 break;
1902 case Reference::ppcFixupAbsHigh16AddLow:
1903 {
1904 int64_t addr = target.getAddress() + ref->getTargetOffset();
1905 if ( !finalLinkedImage && target.isImportProxy() )
1906 addr -= target.getAddress() ;
1907 if ( addr & 0x00008000 )
1908 addr += 0x00010000;
1909 instruction = OSReadBigInt32(instructionPtr, 0);
1910 newInstruction = (instruction & 0xFFFF0000) | (addr >> 16);
1911 OSWriteBigInt32(instructionPtr, 0, newInstruction);
1912 }
1913 break;
1914 case Reference::pointer32Difference:
1915 ENDIAN_WRITE32(*instructionPtr, target.getAddress() + ref->getTargetOffset() - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()));
1916 break;
1917 case Reference::pointer64Difference:
1918 *((uint64_t*)instructionPtr) = ENDIAN_SWAP64(target.getAddress() + ref->getTargetOffset() - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()));
1919 break;
1920 case Reference::x86FixupBranch32:
1921 {
1922 int64_t displacement = target.getAddress() - (this->getAddress() + offset);
1923 if ( target.isImportProxy() ) {
1924 displacement = 0;
1925 }
1926 else {
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";
1931 }
1932 }
1933 OSWriteLittleInt32(instructionPtr, 0, (int32_t)displacement);
1934 }
1935 break;
1936 }
1937 }
1938
1939 // write out
1940 writer.write(0, buffer, getSize());
1941 }
1942
1943
1944
1945 const macho_section* Atom::findSectionFromOffset(macho_uintptr_t offset)
1946 {
1947 const macho_section* const sectionsStart = (const macho_section*)( (char*)fOwner.fSegment + sizeof(macho_segment_command) );
1948 const macho_section* const sectionsEnd = &sectionsStart[fOwner.fSegment->nsects()];
1949 for (const macho_section* s = sectionsStart; s < sectionsEnd; ++s) {
1950 if ( (s->addr() <= offset) && (offset < (s->addr()+s->size())) )
1951 return s;
1952 }
1953 throw "section not found";
1954 }
1955
1956 void Atom::setSize(macho_uintptr_t size)
1957 {
1958 fSize = size;
1959 }
1960
1961
1962 void Atom::setFollowOnAtom(Atom&)
1963 {
1964
1965 }
1966
1967 Reference* Atom::addReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
1968 {
1969 if ( (target.getScope() != ObjectFile::Atom::scopeTranslationUnit) && ((target.fSymbol != NULL) || (target.fSynthesizedName != NULL)) )
1970 return this->addByNameReference(offsetInSrcAtom, kind, target.getName(), offsetInTarget, offsetInFromTarget);
1971 else
1972 return this->addDirectReference(offsetInSrcAtom, kind, target, offsetInTarget, offsetInFromTarget);
1973 }
1974
1975
1976 Reference* Atom::addDirectReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
1977 {
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) ) {
1983 *it = ref;
1984 return ref;
1985 }
1986 }
1987
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);
1990 return ref;
1991 }
1992
1993 Reference* Atom::addByNameReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
1994 {
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);
1998 return ref;
1999 }
2000
2001 Reference* Atom::addDifferenceReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, Atom& fromTarget, uint64_t offsetInFromTarget)
2002 {
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);
2006 return ref;
2007 }
2008
2009
2010 Segment::Segment(const macho_section* sect)
2011 : fSection(sect)
2012 {
2013 }
2014
2015 const char* Segment::getName() const
2016 {
2017 return fSection->segname();
2018 }
2019
2020 bool Segment::isContentReadable() const
2021 {
2022 return true;
2023 }
2024
2025 bool Segment::isContentWritable() const
2026 {
2027 if ( strcmp(fSection->segname(), "__DATA") == 0 )
2028 return true;
2029 if ( strcmp(fSection->segname(), "__OBJC") == 0 )
2030 return true;
2031 return false;
2032 }
2033
2034 bool Segment::isContentExecutable() const
2035 {
2036 return ( strcmp(fSection->segname(), "__TEXT") == 0 );
2037 }
2038
2039
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)
2043 {
2044 }
2045
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)
2049 {
2050 }
2051
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)
2055 {
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();
2060 fTarget = NULL;
2061 }
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;
2067 // }
2068 }
2069
2070
2071
2072 Reference::~Reference()
2073 {
2074 }
2075
2076 bool Reference::isUnbound() const
2077 {
2078 if ( fTarget == NULL )
2079 return true;
2080 if ( (fFromTargetName!=NULL) && (fFromTarget==NULL) )
2081 return true;
2082 return false;
2083 }
2084
2085 bool Reference::isWeakReference() const
2086 {
2087 return fWeak;
2088 }
2089
2090 bool Reference::requiresRuntimeFixUp() const
2091 {
2092 return ( fKind == Reference::pointer );
2093 }
2094
2095 bool Reference::isLazyReference() const
2096 {
2097 return fLazy;
2098 }
2099
2100 ObjectFile::Reference::Kind Reference::getKind() const
2101 {
2102 return fKind;
2103 }
2104
2105 uint64_t Reference::getFixUpOffset() const
2106 {
2107 return fFixUpOffsetInSrc;
2108 }
2109
2110 const char* Reference::getTargetName() const
2111 {
2112 if ( fTargetName != NULL )
2113 return fTargetName;
2114 return fTarget->getName();
2115 }
2116
2117 ObjectFile::Atom& Reference::getTarget() const
2118 {
2119 return *fTarget;
2120 }
2121
2122 void Reference::setTarget(ObjectFile::Atom& target)
2123 {
2124 fTarget = &target;
2125 }
2126
2127
2128 ObjectFile::Atom& Reference::getFromTarget() const
2129 {
2130 return *fFromTarget;
2131 }
2132
2133 const char* Reference::getFromTargetName() const
2134 {
2135 if ( fFromTargetName != NULL )
2136 return fFromTargetName;
2137 return fFromTarget->getName();
2138 }
2139
2140 void Reference::setFromTarget(ObjectFile::Atom& target)
2141 {
2142 fFromTarget = &target;
2143 }
2144
2145 void Reference::setFromTargetName(const char* name)
2146 {
2147 fFromTargetName = name;
2148 }
2149
2150 uint64_t Reference::getTargetOffset() const
2151 {
2152 return fTargetOffset;
2153 }
2154
2155
2156 uint64_t Reference::getFromTargetOffset() const
2157 {
2158 return fFromTargetOffset;
2159 }
2160
2161 void Reference::setLazy(bool lazy)
2162 {
2163 fLazy = lazy;
2164 }
2165
2166 void Reference::setWeak(bool weak)
2167 {
2168 fWeak = weak;
2169 }
2170
2171 const char* Reference::getDescription() const
2172 {
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() );
2183 }
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() );
2193 }
2194 else {
2195 switch( fKind ) {
2196 case noFixUp:
2197 sprintf(temp, "reference to ");
2198 break;
2199 case pointer:
2200 {
2201 const char* weak = "";
2202 if ( fWeak )
2203 weak = "weak ";
2204 const char* lazy = "";
2205 if ( fLazy )
2206 lazy = "lazy ";
2207 sprintf(temp, "offset 0x%04llX, %s%spointer to ", this->getFixUpOffset(), weak, lazy);
2208 }
2209 break;
2210 case ppcFixupBranch14:
2211 case ppcFixupBranch24:
2212 sprintf(temp, "offset 0x%04llX, bl pc-rel fixup to ", this->getFixUpOffset());
2213 break;
2214 case ppcFixupPicBaseLow16:
2215 sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
2216 break;
2217 case ppcFixupPicBaseLow14:
2218 sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
2219 break;
2220 case ppcFixupPicBaseHigh16:
2221 sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
2222 break;
2223 case ppcFixupAbsLow16:
2224 sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", this->getFixUpOffset());
2225 break;
2226 case ppcFixupAbsLow14:
2227 sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", this->getFixUpOffset());
2228 break;
2229 case ppcFixupAbsHigh16:
2230 sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", this->getFixUpOffset());
2231 break;
2232 case ppcFixupAbsHigh16AddLow:
2233 sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", this->getFixUpOffset());
2234 break;
2235 case pointer32Difference:
2236 case pointer64Difference:
2237 // handled above
2238 break;
2239 case x86FixupBranch32:
2240 sprintf(temp, "offset 0x%04llX, call pc-rel fixup to ", this->getFixUpOffset());
2241 break;
2242 }
2243 // always quote by-name references
2244 if ( fTargetName != NULL ) {
2245 strcat(temp, "\"");
2246 strcat(temp, fTargetName);
2247 strcat(temp, "\"");
2248 }
2249 else if ( fTarget != NULL ) {
2250 strcat(temp, fTarget->getDisplayName());
2251 }
2252 else {
2253 strcat(temp, "NULL target");
2254 }
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());
2260 strcat(temp, "\"");
2261 }
2262 }
2263 return temp;
2264 }
2265
2266 };
2267
2268
2269
2270
2271
2272
2273