]> git.saurik.com Git - apple/ld64.git/blob - src/Readers/ObjectFileMachO.cpp
154ff8b7f72264c5d44a0bcba574efdbafecb45b
[apple/ld64.git] / src / Readers / ObjectFileMachO.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
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 isTargetUnbound() const;
38 virtual bool isFromTargetUnbound() const;
39 virtual bool isWeakReference() const;
40 virtual bool requiresRuntimeFixUp(bool slideable) const;
41 virtual bool isLazyReference() const;
42 virtual Kind getKind() const;
43 virtual uint64_t getFixUpOffset() const;
44 virtual const char* getTargetName() const;
45 virtual ObjectFile::Atom& getTarget() const;
46 virtual uint64_t getTargetOffset() const;
47 virtual bool hasFromTarget() const;
48 virtual ObjectFile::Atom& getFromTarget() const;
49 virtual const char* getFromTargetName() const;
50 virtual void setTarget(ObjectFile::Atom&, uint64_t offset);
51 virtual void setFromTarget(ObjectFile::Atom&);
52 virtual void setFromTargetName(const char*);
53 virtual void setFromTargetOffset(uint64_t);
54 virtual const char* getDescription() const;
55 virtual uint64_t getFromTargetOffset() const;
56
57 void setLazy(bool);
58 void setWeak(bool);
59 private:
60 ObjectFile::Atom* fTarget;
61 ObjectFile::Atom* fFromTarget;
62 const char* fTargetName;
63 const char* fFromTargetName;
64 macho_uintptr_t fTargetOffset;
65 macho_uintptr_t fFromTargetOffset;
66 macho_uintptr_t fFixUpOffsetInSrc;
67 Kind fKind;
68 bool fLazy;
69 bool fWeak;
70 };
71
72
73
74 class Reader : public ObjectFile::Reader
75 {
76 public:
77 Reader(const char* path);
78 Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options);
79 virtual ~Reader();
80
81 virtual const char* getPath();
82 virtual std::vector<class ObjectFile::Atom*>& getAtoms();
83 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name);
84 virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo(); // stabs info not associated with an atom
85
86
87 private:
88 friend class Atom;
89 void init(const macho_header* header, const char* path);
90 void buildOffsetsSet(const macho_relocation_info* reloc, const macho_section* sect, std::set<uint32_t>& offsets, std::set<uint32_t>& dontUse);
91 void addRelocReference(const macho_section* sect, const macho_relocation_info* reloc);
92 Atom* findAtomCoveringOffset(uint32_t offset);
93 uint32_t findAtomIndex(const Atom& atom);
94 void addFixUp(uint32_t srcAddr, uint32_t dstAddr, Reference::Kind kind, uint32_t picBaseAddr);
95 class Segment* makeSegmentFromSection(const macho_section*);
96 macho_uintptr_t commonsOffset();
97 void insertOffsetIfText(std::set<uint32_t>& offsets, uint32_t value);
98 void insertOffsetIfNotText(std::set<uint32_t>& offsets, uint32_t value);
99 const macho_section* findSectionCoveringOffset(uint32_t offset);
100 void addCallSiteReference(Atom& src, uint32_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint32_t picBaseOffset, uint32_t offsetInTargetAtom);
101 void deadStub(Atom& target);
102
103 const char* fPath;
104 const ObjectFile::ReaderOptions& fOptions;
105 const macho_header* fHeader;
106 const char* fStrings;
107 const macho_nlist* fSymbols;
108 uint32_t fSymbolCount;
109 const macho_segment_command* fSegment;
110 const uint32_t* fIndirectTable;
111 std::vector<class Atom*> fAtoms;
112 std::vector<class Segment*> fSegments;
113 std::set<class ObjectFile::Atom*> fDeadAtoms;
114 uint32_t fNonAtomStabsStartIndex;
115 uint32_t fNonAtomStabsCount;
116 std::vector<uint32_t> fNonAtomExtras;
117 };
118
119 class Segment : public ObjectFile::Segment
120 {
121 public:
122 virtual const char* getName() const;
123 virtual bool isContentReadable() const;
124 virtual bool isContentWritable() const;
125 virtual bool isContentExecutable() const;
126 protected:
127 Segment(const macho_section*);
128 friend class Reader;
129 private:
130 const macho_section* fSection;
131 };
132
133 class Atom : public ObjectFile::Atom
134 {
135 public:
136 virtual ObjectFile::Reader* getFile() const;
137 virtual const char* getName() const;
138 virtual const char* getDisplayName() const;
139 virtual Scope getScope() const;
140 virtual bool isTentativeDefinition() const;
141 virtual bool isWeakDefinition() const;
142 virtual bool isCoalesableByName() const;
143 virtual bool isCoalesableByValue() const;
144 virtual bool isZeroFill() const;
145 virtual bool dontDeadStrip() const;
146 virtual bool dontStripName() const; // referenced dynamically
147 virtual bool isImportProxy() const;
148 virtual uint64_t getSize() const;
149 virtual std::vector<ObjectFile::Reference*>& getReferences() const;
150 virtual bool mustRemainInSection() const;
151 virtual const char* getSectionName() const;
152 virtual Segment& getSegment() const;
153 virtual bool requiresFollowOnAtom() const;
154 virtual ObjectFile::Atom& getFollowOnAtom() const;
155 virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo() const;
156 virtual uint8_t getAlignment() const;
157 virtual WeakImportSetting getImportWeakness() const { return ObjectFile::Atom::kWeakUnset; }
158 virtual void copyRawContent(uint8_t buffer[]) const;
159 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
160 virtual void setScope(Scope);
161 virtual void setImportWeakness(bool weakImport) { }
162
163 bool isLazyStub();
164
165 protected:
166 friend class Reader;
167 Atom(Reader&, const macho_nlist*);
168 Atom(Reader&, uint32_t offset);
169 virtual ~Atom();
170
171 const macho_section* findSectionFromOffset(uint32_t offset);
172 const macho_section* getCommonsSection();
173 void setSize(macho_uintptr_t);
174 void setFollowOnAtom(Atom&);
175 static bool atomCompare(const Atom* lhs, const Atom* rhs);
176 Reference* addDirectReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
177 Reference* addByNameReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
178 Reference* addDifferenceReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, Atom& fromTarget, uint64_t offsetInFromTarget);
179 Reference* addReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
180
181 Reader& fOwner;
182 const macho_nlist* fSymbol;
183 macho_uintptr_t fOffset;
184 macho_uintptr_t fSize;
185 const macho_section* fSection;
186 Segment* fSegment;
187 const char* fSynthesizedName;
188 std::vector<class Reference*> fReferences;
189 ObjectFile::Atom::Scope fScope;
190 uint32_t fStabsStartIndex;
191 uint32_t fStabsCount;
192
193 static macho_section fgCommonsSection; // for us by tentative definitions
194 };
195
196
197 Reader* MakeReader(const macho_header* mh, const char* path, const ObjectFile::ReaderOptions& options)
198 {
199 return new Reader(mh, path, options);
200 }
201
202
203 Reader::Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options)
204 : fPath(NULL), fOptions(options), fHeader(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL)
205 {
206 init(header, path);
207 }
208
209 Reader::Reader(const char* path)
210 : fPath(NULL), fOptions(*(new ObjectFile::ReaderOptions())), fHeader(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL),
211 fIndirectTable(NULL), fNonAtomStabsStartIndex(0), fNonAtomStabsCount(0)
212 {
213 struct stat stat_buf;
214
215 int fd = ::open(path, O_RDONLY, 0);
216 ::fstat(fd, &stat_buf);
217 void* p = ::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE, fd, 0);
218 ::close(fd);
219 if ( ((macho_header*)p)->magic() == MH_MAGIC ) {
220 init((macho_header*)p, path);
221 return;
222 }
223 throw "add fat handling";
224 }
225
226
227 Reader::~Reader()
228 {
229 }
230
231
232 bool Atom::atomCompare(const Atom* lhs, const Atom* rhs)
233 {
234 return lhs->fOffset < rhs->fOffset;
235 }
236
237
238
239 void Reader::init(const macho_header* header, const char* path)
240 {
241 // sanity check
242 #if defined(ARCH_PPC)
243 if ( (header->magic() != MH_MAGIC) || (header->cputype() != CPU_TYPE_POWERPC) )
244 throw "not a valid ppc mach-o file";
245 #elif defined(ARCH_I386)
246 if ( (header->magic() != MH_MAGIC) || (header->cputype() != CPU_TYPE_I386) )
247 throw "not a valid i386 mach-o file";
248 #elif defined(ARCH_PPC64)
249 if ( (header->magic() != MH_MAGIC_64) || (header->cputype() != CPU_TYPE_POWERPC64) )
250 throw "not a valid ppc64 mach-o file";
251 #endif
252
253 // cache intersting pointers
254 fPath = strdup(path);
255 fHeader = header;
256 const uint32_t cmd_count = header->ncmds();
257 const macho_load_command* const cmds = (macho_load_command*)((char*)header + macho_header::size);
258 const macho_load_command* cmd = cmds;
259 for (uint32_t i = 0; i < cmd_count; ++i) {
260 switch (cmd->cmd()) {
261 case LC_SYMTAB:
262 {
263 const macho_symtab_command* symtab = (macho_symtab_command*)cmd;
264 fSymbolCount = symtab->nsyms();
265 fSymbols = (const macho_nlist*)((char*)header + symtab->symoff());
266 fStrings = (char*)header + symtab->stroff();
267 }
268 break;
269 case LC_DYSYMTAB:
270 {
271 const macho_dysymtab_command* dsymtab = (struct macho_dysymtab_command*)cmd;
272 fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
273 }
274 break;
275 default:
276 if ( cmd->cmd() == macho_segment_command::command ) {
277 fSegment= (macho_segment_command*)cmd;
278 }
279 break;
280 }
281 cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
282 }
283
284 // add all atoms that have entries in symbol table
285 std::set<uint32_t> symbolAtomOffsets;
286 for (uint32_t i=0; i < fSymbolCount; ++i) {
287 const macho_nlist& sym = fSymbols[i];
288 if ( (sym.n_type() & N_STAB) == 0 ) {
289 uint8_t type = (sym.n_type() & N_TYPE);
290 if ( (type == N_SECT) || ((type == N_UNDF) && (sym.n_value() != 0)) ) {
291 // real definition or "tentative definition"
292 Atom* newAtom = new Atom(*this, &sym);
293 fAtoms.push_back(newAtom);
294 symbolAtomOffsets.insert(newAtom->fOffset);
295 }
296 }
297 }
298
299 // add all points referenced in relocations
300 const macho_section* const sectionsStart = (macho_section*)((char*)fSegment + sizeof(macho_segment_command));
301 const macho_section* const sectionsEnd = &sectionsStart[fSegment->nsects()];
302 std::set<uint32_t> cleavePoints;
303 std::set<uint32_t> dontCleavePoints;
304 for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
305 const macho_relocation_info* relocs = (macho_relocation_info*)((char*)(fHeader) + sect->reloff());
306 const uint32_t relocCount = sect->nreloc();
307 for (uint32_t r = 0; r < relocCount; ++r) {
308 buildOffsetsSet(&relocs[r], sect, cleavePoints, dontCleavePoints);
309 }
310 }
311 // add all stub functions and (non)lazy pointers
312 std::set<uint32_t> deadStubOffsets;
313 for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
314 uint8_t type (sect->flags() & SECTION_TYPE);
315 switch ( type ) {
316 case S_SYMBOL_STUBS:
317 {
318 const uint32_t stubSize = sect->reserved2();
319 // TVector glue sections are marked as S_SYMBOL_STUBS but are only 8 bytes
320 if ( stubSize > 8 ) {
321 for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += stubSize) {
322 uint32_t stubAddr = sect->addr() + sectOffset;
323 if ( cleavePoints.count(stubAddr) == 0 ) {
324 cleavePoints.insert(stubAddr);
325 deadStubOffsets.insert(stubAddr);
326 }
327 }
328 }
329 }
330 break;
331 case S_NON_LAZY_SYMBOL_POINTERS:
332 case S_LAZY_SYMBOL_POINTERS:
333 for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += sizeof(macho_uintptr_t)) {
334 uint32_t pointerAddr = sect->addr() + sectOffset;
335 cleavePoints.insert(pointerAddr);
336 }
337 break;
338 }
339 // also make sure each section break is a cleave point
340 if ( sect->size() != 0 )
341 cleavePoints.insert(sect->addr());
342 }
343
344 for (std::set<uint32_t>::iterator it=cleavePoints.begin(); it != cleavePoints.end(); it++) {
345 uint32_t cleavePoint = *it;
346 //printf("cleave offset 0x%08X, don't cleave=%d, isSymbol=%d\n", cleavePoint, dontCleavePoints.count(cleavePoint), symbolAtomOffsets.count(cleavePoint));
347 // only create an atom if it is not a don't-cleave point and there is not already an atom at this offset
348 if ( (dontCleavePoints.count(cleavePoint) == 0) && (symbolAtomOffsets.count(cleavePoint) == 0) )
349 fAtoms.push_back(new Atom(*this, cleavePoint));
350 }
351
352 const uint32_t atomCount = fAtoms.size();
353 if ( atomCount > 0 ) {
354 // sort the atoms so the occur in source file order
355 std::sort(fAtoms.begin(), fAtoms.end(), Atom::atomCompare);
356
357 // tell each atom its size and follow on
358 const bool dontDeadStrip = ((fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0);
359 Atom* lastAtom = fAtoms[0];
360 for (uint32_t i=1; i < atomCount; ++i) {
361 Atom* thisAtom = fAtoms[i];
362 if ( lastAtom->getSize() == 0 ) {
363 if ( lastAtom->fSection == thisAtom->fSection )
364 lastAtom->setSize(thisAtom->fOffset - lastAtom->fOffset);
365 else
366 lastAtom->setSize(lastAtom->fSection->addr() + lastAtom->fSection->size() - lastAtom->fOffset);
367 }
368 if ( dontDeadStrip )
369 lastAtom->setFollowOnAtom(*thisAtom);
370 lastAtom = thisAtom;
371 }
372 lastAtom = fAtoms[atomCount-1];
373 if ( lastAtom->getSize() == 0 )
374 lastAtom->setSize(lastAtom->fSection->addr() + lastAtom->fSection->size() - lastAtom->fOffset);
375
376 // add relocation based references
377 for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
378 const macho_relocation_info* relocs = (macho_relocation_info*)((char*)(fHeader) + sect->reloff());
379 const uint32_t relocCount = sect->nreloc();
380 for (uint32_t r = 0; r < relocCount; ++r) {
381 addRelocReference(sect, &relocs[r]);
382 }
383 }
384
385 // add dead stubs to list to delete
386 for (std::set<uint32_t>::iterator it=deadStubOffsets.begin(); it != deadStubOffsets.end(); it++) {
387 Atom* deadStub = findAtomCoveringOffset(*it);
388 this->deadStub(*deadStub);
389 }
390
391 // remove dead stubs and lazy pointers
392 for (std::set<ObjectFile::Atom*>::iterator deadIt=fDeadAtoms.begin(); deadIt != fDeadAtoms.end(); deadIt++) {
393 for (std::vector<Atom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
394 if ( *deadIt == *it ) {
395 fAtoms.erase(it);
396 break;
397 }
398 }
399 }
400
401 }
402
403 // process stabs debugging info
404 if ( ! fOptions.fStripDebugInfo ) {
405 // scan symbol table for stabs entries
406 fNonAtomStabsStartIndex = 0xFFFFFFFF;
407 fNonAtomStabsCount = 0;
408 uint32_t possibleStart = 0;
409 Atom* atom = NULL;
410 const uint32_t atomCount = fAtoms.size();
411 enum { start, inBeginEnd, foundFirst, inFunction } state = start;
412 for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
413 const macho_nlist* sym = &fSymbols[symbolIndex];
414 uint8_t type = sym->n_type();
415 if ( (type & N_STAB) != 0 ) {
416 if ( fNonAtomStabsStartIndex == 0xFFFFFFFF )
417 fNonAtomStabsStartIndex = symbolIndex;
418 switch (state) {
419 case start:
420 if ( (type == N_SLINE) || (type == N_SOL) ) {
421 possibleStart = symbolIndex;
422 state = foundFirst;
423 }
424 else if ( type == N_BNSYM ) {
425 macho_uintptr_t targetAddr = sym->n_value();
426 atom = this->findAtomCoveringOffset(targetAddr);
427 if ( (atom != NULL) || (atom->fOffset == targetAddr) ) {
428 atom->fStabsStartIndex = symbolIndex;
429 if ( fNonAtomStabsCount == 0 )
430 fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex;
431 }
432 else {
433 fprintf(stderr, "can't find atom for stabs 0x%02X at %08X in %s\n", type, targetAddr, path);
434 atom = NULL;
435 }
436 state = inBeginEnd;
437 }
438 else if ( (type == N_STSYM) || (type == N_LCSYM) ) {
439 macho_uintptr_t targetAddr = sym->n_value();
440 atom = this->findAtomCoveringOffset(targetAddr);
441 if ( (atom != NULL) || (atom->fOffset == targetAddr) ) {
442 atom->fStabsStartIndex = symbolIndex;
443 atom->fStabsCount = 1;
444 if ( fNonAtomStabsCount == 0 )
445 fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex;
446 }
447 else {
448 fprintf(stderr, "can't find atom for stabs 0x%02X at %08X in %s\n", type, targetAddr, path);
449 atom = NULL;
450 }
451 }
452 else if ( type == N_GSYM ) {
453 // n_value field is NOT atom address ;-(
454 // need to find atom by name match
455 const char* symString = &fStrings[sym->n_strx()];
456 const char* colon = strchr(symString, ':');
457 bool found = false;
458 if ( colon != NULL ) {
459 int nameLen = colon - symString;
460 for (uint32_t searchIndex = 0; searchIndex < atomCount; ++searchIndex) {
461 const char* atomName = fAtoms[searchIndex]->getName();
462 if ( (atomName != NULL) && (strncmp(&atomName[1], symString, nameLen) == 0) ) {
463 atom = fAtoms[searchIndex];
464 atom->fStabsStartIndex = symbolIndex;
465 atom->fStabsCount = 1;
466 if ( fNonAtomStabsCount == 0 )
467 fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex;
468 found = true;
469 break;
470 }
471 }
472 }
473 if ( !found ) {
474 fprintf(stderr, "can't find atom for N_GSYM stabs %s in %s\n", symString, path);
475 atom = NULL;
476 }
477 }
478 else if ( type == N_LSYM ) {
479 if ( fNonAtomStabsCount != 0 ) {
480 // built with -gfull and some type definition not at start of source
481 fNonAtomExtras.push_back(symbolIndex);
482 }
483 }
484 break;
485 case inBeginEnd:
486 if ( type == N_ENSYM ) {
487 state = start;
488 if ( atom != NULL )
489 atom->fStabsCount = symbolIndex - atom->fStabsStartIndex + 1;
490 }
491 break;
492 case foundFirst:
493 if ( (type == N_FUN) && (sym->n_sect() != 0) ) {
494 state = inFunction;
495 macho_uintptr_t targetAddr = sym->n_value();
496 atom = this->findAtomCoveringOffset(targetAddr);
497 if ( (atom == NULL) || (atom->fOffset != targetAddr) ) {
498 fprintf(stderr, "can't find atom for stabs FUN index: %d at 0x%08llX in %s\n", symbolIndex, (uint64_t)targetAddr, path);
499 atom = NULL;
500 }
501 else {
502 atom->fStabsStartIndex = possibleStart;
503 if ( fNonAtomStabsCount == 0 )
504 fNonAtomStabsCount = possibleStart - fNonAtomStabsStartIndex;
505 }
506 }
507 else if ( (type == N_FUN) && (sym->n_sect() == 0) ) {
508 fprintf(stderr, "end stab FUN found without start FUN, index=%d in %s\n", symbolIndex, path);
509 state = start;
510 }
511 break;
512 case inFunction:
513 if ( (type == N_FUN) && (sym->n_sect() == 0) ) {
514 state = start;
515 if ( atom != NULL )
516 atom->fStabsCount = symbolIndex - atom->fStabsStartIndex + 1;
517 }
518 break;
519 }
520 }
521 }
522
523 }
524 }
525
526
527 void Reader::addRelocReference(const macho_section* sect, const macho_relocation_info* reloc)
528 {
529 uint32_t srcAddr;
530 uint32_t dstAddr;
531 Atom* src;
532 Atom* dst;
533 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
534 uint32_t instruction;
535 #endif
536 uint32_t* fixUpPtr;
537 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
538 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
539 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
540 const macho_relocation_info* nextReloc = &reloc[1];
541 #endif
542 switch ( reloc->r_type() ) {
543 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
544 case PPC_RELOC_BR24:
545 {
546 if ( reloc->r_extern() ) {
547 instruction = OSSwapBigToHostInt32(*fixUpPtr);
548 int32_t displacement = (instruction & 0x03FFFFFC);
549 if ( (displacement & 0x02000000) != 0 )
550 displacement |= 0xFC000000;
551 uint32_t offsetInTarget = sect->addr() + reloc->r_address() + displacement;
552 srcAddr = sect->addr() + reloc->r_address();
553 src = findAtomCoveringOffset(srcAddr);
554 const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
555 const char* targetName = &fStrings[targetSymbol->n_strx()];
556 src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupBranch24, targetName, offsetInTarget, 0);
557 }
558 else {
559 instruction = OSSwapBigToHostInt32(*fixUpPtr);
560 if ( (instruction & 0x4C000000) == 0x48000000 ) {
561 int32_t displacement = (instruction & 0x03FFFFFC);
562 if ( (displacement & 0x02000000) != 0 )
563 displacement |= 0xFC000000;
564 srcAddr = sect->addr() + reloc->r_address();
565 dstAddr = srcAddr + displacement;
566 src = findAtomCoveringOffset(srcAddr);
567 dst = findAtomCoveringOffset(dstAddr);
568 this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch24, *dst, 0, dstAddr - dst->fOffset);
569 }
570 }
571 }
572 break;
573 case PPC_RELOC_BR14:
574 {
575 if ( reloc->r_extern() ) {
576 srcAddr = sect->addr() + reloc->r_address();
577 src = findAtomCoveringOffset(srcAddr);
578 const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
579 const char* targetName = &fStrings[targetSymbol->n_strx()];
580 src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupBranch14, targetName, 0, 0);
581 }
582 else {
583 instruction = OSSwapBigToHostInt32(*fixUpPtr);
584 int32_t displacement = (instruction & 0x0000FFFC);
585 if ( (displacement & 0x00008000) != 0 )
586 displacement |= 0xFFFF0000;
587 srcAddr = sect->addr() + reloc->r_address();
588 dstAddr = srcAddr + displacement;
589 src = findAtomCoveringOffset(srcAddr);
590 dst = findAtomCoveringOffset(dstAddr);
591 this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch14, *dst, 0, dstAddr - dst->fOffset);
592 }
593 }
594 break;
595 case PPC_RELOC_PAIR:
596 // skip, processed by a previous look ahead
597 break;
598 case PPC_RELOC_LO16:
599 {
600 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
601 printf("PPC_RELOC_LO16 missing following pair\n");
602 break;
603 }
604 srcAddr = sect->addr() + reloc->r_address();
605 if ( reloc->r_extern() ) {
606 const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
607 const char* targetName = &fStrings[targetSymbol->n_strx()];
608 src = findAtomCoveringOffset(srcAddr);
609 instruction = OSSwapBigToHostInt32(*fixUpPtr);
610 dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFF);
611 src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow16, targetName, dstAddr, 0);
612 }
613 else {
614 instruction = OSSwapBigToHostInt32(*fixUpPtr);
615 int16_t lowBits = (instruction & 0xFFFF);
616 dstAddr = (nextReloc->r_address() << 16) + (int32_t)lowBits;
617 if ( (lowBits & 0x8000) != 0 )
618 dstAddr += 0x10000;
619 addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsLow16, 0);
620 }
621 }
622 break;
623 case PPC_RELOC_LO14:
624 {
625 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
626 printf("PPC_RELOC_LO14 missing following pair\n");
627 break;
628 }
629 srcAddr = sect->addr() + reloc->r_address();
630 if ( reloc->r_extern() ) {
631 const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
632 const char* targetName = &fStrings[targetSymbol->n_strx()];
633 src = findAtomCoveringOffset(srcAddr);
634 instruction = OSSwapBigToHostInt32(*fixUpPtr);
635 dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC);
636 src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow14, targetName, dstAddr, 0);
637 }
638 else {
639 instruction = OSSwapBigToHostInt32(*fixUpPtr);
640 dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC);
641 addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsLow14, 0);
642 }
643 }
644 break;
645 case PPC_RELOC_HI16:
646 {
647 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
648 printf("PPC_RELOC_HI16 missing following pair\n");
649 break;
650 }
651 srcAddr = sect->addr() + reloc->r_address();
652 if ( reloc->r_extern() ) {
653 const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
654 const char* targetName = &fStrings[targetSymbol->n_strx()];
655 src = findAtomCoveringOffset(srcAddr);
656 instruction = OSSwapBigToHostInt32(*fixUpPtr);
657 dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
658 src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16, targetName, dstAddr, 0);
659 }
660 else {
661 instruction = OSSwapBigToHostInt32(*fixUpPtr);
662 dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
663 addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsHigh16, 0);
664 }
665 }
666 break;
667 case PPC_RELOC_HA16:
668 {
669 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
670 printf("PPC_RELOC_HA16 missing following pair\n");
671 break;
672 }
673 srcAddr = sect->addr() + reloc->r_address();
674 if ( reloc->r_extern() ) {
675 const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
676 const char* targetName = &fStrings[targetSymbol->n_strx()];
677 instruction = OSSwapBigToHostInt32(*fixUpPtr);
678 int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF);
679 dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
680 src = findAtomCoveringOffset(srcAddr);
681 src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16AddLow, targetName, dstAddr, 0);
682 }
683 else {
684 instruction = OSSwapBigToHostInt32(*fixUpPtr);
685 int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF);
686 dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
687 addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsHigh16AddLow, 0);
688 }
689 }
690 break;
691 case GENERIC_RELOC_VANILLA:
692 {
693 srcAddr = sect->addr() + reloc->r_address();
694 Atom* srcAtom = findAtomCoveringOffset(srcAddr);
695 uint32_t offsetInSrcAtom = srcAddr - srcAtom->fOffset;
696 macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
697 if ( reloc->r_extern() ) {
698 const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
699 uint8_t type = targetSymbol->n_type() & N_TYPE;
700 if ( type == N_UNDF ) {
701 const char* targetName = &fStrings[targetSymbol->n_strx()];
702 macho_uintptr_t addend = pointerValue;
703 // ppc lazy pointers have initial reference to dyld_stub_binding_helper
704 if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
705 std::vector<ObjectFile::Reference*>& refs = srcAtom->getReferences();
706 if ( refs.size() > 0 ) {
707 Reference* ref = (Reference*)refs[0];
708 #if defined(ARCH_PPC64)
709 // hack to work around bad crt1.o in Mac OS X 10.4
710 targetName = "dyld_stub_binding_helper";
711 #endif
712 ref->setFromTargetName(targetName);
713 }
714 else {
715 fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size());
716 }
717 }
718 #if defined(ARCH_PPC64)
719 // hack to work around bad crt1.o in Mac OS X 10.4
720 else if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) {
721 // ignore extra relocation
722 }
723 #endif
724 else {
725 srcAtom->addByNameReference(offsetInSrcAtom, Reference::pointer, targetName, addend, 0);
726 }
727 }
728 else {
729 dstAddr = targetSymbol->n_value();
730 Atom* dstAtom = findAtomCoveringOffset(dstAddr);
731 macho_uintptr_t addend = pointerValue;
732 // ppc lazy pointers have initial reference to dyld_stub_binding_helper
733 if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
734 std::vector<ObjectFile::Reference*>& refs = srcAtom->getReferences();
735 if ( refs.size() > 0 ) {
736 Reference* ref = (Reference*)refs[0];
737 ref->setFromTarget(*dstAtom);
738 ref->setFromTargetOffset(dstAddr - dstAtom->fOffset);
739 }
740 else {
741 fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size());
742 }
743 }
744 else {
745 srcAtom->addReference(offsetInSrcAtom, Reference::pointer, *dstAtom, addend, 0);
746 }
747 }
748 }
749 else {
750 Atom* dstAtom = findAtomCoveringOffset(pointerValue);
751 // lazy pointers have references to dyld_stub_binding_helper which need to be ignored
752 if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
753 std::vector<ObjectFile::Reference*>& refs = srcAtom->getReferences();
754 if ( refs.size() > 0 ) {
755 Reference* ref = (Reference*)refs[0];
756 ref->setFromTarget(*dstAtom);
757 ref->setFromTargetOffset(pointerValue - dstAtom->fOffset);
758 }
759 else {
760 fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size());
761 }
762 }
763 else {
764 srcAtom->addReference(offsetInSrcAtom, Reference::pointer, *dstAtom, pointerValue-dstAtom->fOffset, 0);
765 }
766 }
767 }
768 break;
769 case PPC_RELOC_JBSR:
770 // ignore for now
771 break;
772 #endif
773 #if defined(ARCH_I386)
774 case GENERIC_RELOC_VANILLA:
775 {
776 srcAddr = sect->addr() + reloc->r_address();
777 src = findAtomCoveringOffset(srcAddr);
778 if ( reloc->r_length() != 2 )
779 throw "bad vanilla relocation length";
780 Reference::Kind kind;
781 macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
782 if ( reloc->r_pcrel() ) {
783 kind = Reference::x86FixupBranch32;
784 pointerValue += srcAddr + sizeof(macho_uintptr_t);
785 }
786 else {
787 kind = Reference::pointer;
788 }
789 uint32_t offsetInSrcAtom = srcAddr - src->fOffset;
790 if ( reloc->r_extern() ) {
791 const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
792 uint8_t type = targetSymbol->n_type() & N_TYPE;
793 if ( type == N_UNDF ) {
794 const char* targetName = &fStrings[targetSymbol->n_strx()];
795 macho_uintptr_t addend = pointerValue;
796 src->addByNameReference(offsetInSrcAtom, kind, targetName, addend, 0);
797 }
798 else {
799 dstAddr = targetSymbol->n_value();
800 dst = findAtomCoveringOffset(dstAddr);
801 macho_uintptr_t addend = pointerValue - dstAddr;
802 src->addReference(offsetInSrcAtom, kind, *dst, addend, 0);
803 }
804 }
805 else {
806 dst = findAtomCoveringOffset(pointerValue);
807 // lazy pointers have references to dyld_stub_binding_helper which need to be ignored
808 if ( (src->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
809 std::vector<ObjectFile::Reference*>& refs = src->getReferences();
810 if ( refs.size() == 1 ) {
811 Reference* ref = (Reference*)refs[0];
812 ref->setFromTarget(*dst);
813 ref->setFromTargetOffset(pointerValue - dst->fOffset);
814 }
815 else {
816 fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", src->getDisplayName(), refs.size());
817 }
818 }
819 else if ( ((uint8_t*)fixUpPtr)[-1] == 0xE8 ) // special case call instruction
820 this->addCallSiteReference(*src, offsetInSrcAtom, kind, *dst, 0, pointerValue - dst->fOffset);
821 else
822 src->addReference(offsetInSrcAtom, kind, *dst, 0, 0);
823 }
824 }
825 break;
826 #endif
827
828 default:
829 printf("unknown relocation type %d\n", reloc->r_type());
830 }
831 }
832 else {
833 const macho_scattered_relocation_info* sreloc = (macho_scattered_relocation_info*)reloc;
834 srcAddr = sect->addr() + sreloc->r_address();
835 dstAddr = sreloc->r_value();
836 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
837 const macho_scattered_relocation_info* nextSReloc = &sreloc[1];
838 const macho_relocation_info* nextReloc = &reloc[1];
839 // file format allows pair to be scattered or not
840 bool nextRelocIsPair = false;
841 uint32_t nextRelocAddress = 0;
842 uint32_t nextRelocValue = 0;
843 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
844 if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
845 nextRelocIsPair = true;
846 nextRelocAddress = nextReloc->r_address();
847 }
848 }
849 else {
850 if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
851 nextRelocIsPair = true;
852 nextRelocAddress = nextSReloc->r_address();
853 nextRelocValue = nextSReloc->r_value();
854 }
855 }
856 switch (sreloc->r_type()) {
857 case GENERIC_RELOC_VANILLA:
858 {
859 macho_uintptr_t betterDstAddr = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
860 //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr);
861 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
862 Atom* src = findAtomCoveringOffset(srcAddr);
863 Atom* dst = findAtomCoveringOffset(dstAddr);
864 src->addReference(srcAddr - src->fOffset, Reference::pointer, *dst, betterDstAddr - dst->fOffset, 0);
865 }
866 break;
867 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
868 case PPC_RELOC_BR24:
869 {
870 instruction = OSSwapBigToHostInt32(*fixUpPtr);
871 if ( (instruction & 0x4C000000) == 0x48000000 ) {
872 int32_t displacement = (instruction & 0x03FFFFFC);
873 if ( (displacement & 0x02000000) != 0 )
874 displacement |= 0xFC000000;
875 srcAddr = sect->addr() + sreloc->r_address();
876 dstAddr = sreloc->r_value();
877 src = findAtomCoveringOffset(srcAddr);
878 dst = findAtomCoveringOffset(dstAddr);
879 this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch24, *dst, 0, srcAddr + displacement - sreloc->r_value());
880 }
881 }
882 break;
883 case PPC_RELOC_LO16_SECTDIFF:
884 {
885 if ( ! nextRelocIsPair) {
886 printf("PPC_RELOC_LO16_SECTDIFF missing following PAIR\n");
887 break;
888 }
889 src = findAtomCoveringOffset(srcAddr);
890 dst = findAtomCoveringOffset(dstAddr);
891 instruction = OSSwapBigToHostInt32(*fixUpPtr);
892 int16_t lowBits = (instruction & 0xFFFF);
893 int32_t displacement = (nextRelocAddress << 16) + (int32_t)lowBits;
894 if ( (lowBits & 0x8000) != 0 )
895 displacement += 0x10000;
896 uint32_t picBaseOffset = nextRelocValue - src->fOffset;
897 int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset;
898 src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseLow16, *dst, dstOffset, picBaseOffset);
899 }
900 break;
901 case PPC_RELOC_LO14_SECTDIFF:
902 {
903 if ( ! nextRelocIsPair) {
904 printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
905 break;
906 }
907 src = findAtomCoveringOffset(srcAddr);
908 dst = findAtomCoveringOffset(dstAddr);
909 instruction = OSSwapBigToHostInt32(*fixUpPtr);
910 int16_t lowBits = (instruction & 0xFFFC);
911 int32_t displacement = (nextRelocAddress << 16) + (int32_t)lowBits;
912 if ( (lowBits & 0x8000) != 0 )
913 displacement += 0x10000;
914 uint32_t picBaseOffset = nextRelocValue - src->fOffset;
915 int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset;
916 src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseLow14, *dst, dstOffset, picBaseOffset);
917 }
918 break;
919 case PPC_RELOC_HA16_SECTDIFF:
920 {
921 if ( ! nextRelocIsPair) {
922 printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
923 break;
924 }
925 src = findAtomCoveringOffset(srcAddr);
926 dst = findAtomCoveringOffset(dstAddr);
927 instruction = OSSwapBigToHostInt32(*fixUpPtr);
928 int16_t lowBits = (nextRelocAddress & 0x0000FFFF);
929 int32_t displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
930 uint32_t picBaseOffset = nextRelocValue - src->fOffset;
931 int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset;
932 src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseHigh16, *dst, dstOffset, picBaseOffset);
933 }
934 break;
935 case PPC_RELOC_LO14:
936 {
937 if ( ! nextRelocIsPair) {
938 printf("PPC_RELOC_LO14 missing following PAIR\n");
939 break;
940 }
941 src = findAtomCoveringOffset(srcAddr);
942 dst = findAtomCoveringOffset(dstAddr);
943 instruction = OSSwapBigToHostInt32(*fixUpPtr);
944 int16_t lowBits = (instruction & 0xFFFC);
945 uint32_t betterDstAddr = (nextRelocAddress << 16) + (int32_t)lowBits;
946 if ( (lowBits & 0x8000) != 0 )
947 betterDstAddr += 0x10000;
948 src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow14, *dst, betterDstAddr - dst->fOffset, 0);
949 }
950 break;
951 case PPC_RELOC_LO16:
952 {
953 if ( ! nextRelocIsPair) {
954 printf("PPC_RELOC_LO16 missing following PAIR\n");
955 break;
956 }
957 src = findAtomCoveringOffset(srcAddr);
958 dst = findAtomCoveringOffset(dstAddr);
959 instruction = OSSwapBigToHostInt32(*fixUpPtr);
960 int16_t lowBits = (instruction & 0xFFFF);
961 uint32_t betterDstAddr = (nextRelocAddress << 16) + (int32_t)lowBits;
962 if ( (lowBits & 0x8000) != 0 )
963 betterDstAddr += 0x10000;
964 src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow16, *dst, betterDstAddr - dst->fOffset, 0);
965 }
966 break;
967 case PPC_RELOC_HA16:
968 {
969 if ( ! nextRelocIsPair) {
970 printf("PPC_RELOC_HA16 missing following PAIR\n");
971 break;
972 }
973 src = findAtomCoveringOffset(srcAddr);
974 dst = findAtomCoveringOffset(dstAddr);
975 instruction = OSSwapBigToHostInt32(*fixUpPtr);
976 int16_t lowBits = (nextRelocAddress & 0xFFFF);
977 uint32_t betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
978 src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16AddLow, *dst, betterDstAddr - dst->fOffset, 0);
979 }
980 break;
981 case PPC_RELOC_SECTDIFF:
982 case PPC_RELOC_LOCAL_SECTDIFF:
983 {
984 const macho_scattered_relocation_info* nextReloc = &sreloc[1];
985 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
986 printf("PPC_RELOC_SECTDIFF missing following pair\n");
987 break;
988 }
989 srcAddr = sect->addr() + sreloc->r_address();
990 uint32_t toAddr = sreloc->r_value();
991 uint32_t fromAddr = nextReloc->r_value();
992 src = findAtomCoveringOffset(srcAddr);
993 Atom* to = findAtomCoveringOffset(toAddr);
994 Atom* from = findAtomCoveringOffset(fromAddr);
995 //macho_intptr_t pointerValue = *(macho_intptr_t*)fixUpPtr;
996 //uint64_t toOffset = to->fOffset;
997 //uint64_t fromOffset = from->fOffset;
998 //int64_t pointerValue64 = pointerValue;
999 //uint64_t addend = pointerValue64 - (toOffset - fromOffset);
1000 Reference::Kind kind = Reference::pointer32Difference;
1001 if ( sreloc->r_length() == 3 )
1002 kind = Reference::pointer64Difference;
1003 src->addDifferenceReference(srcAddr - src->fOffset, kind, *to, toAddr - to->fOffset, *from, fromAddr - from->fOffset);
1004 }
1005 break;
1006 case PPC_RELOC_PAIR:
1007 break;
1008 case PPC_RELOC_HI16_SECTDIFF:
1009 printf("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF\n");
1010 break;
1011 #endif
1012 #if defined(ARCH_I386)
1013 case GENERIC_RELOC_SECTDIFF:
1014 case GENERIC_RELOC_LOCAL_SECTDIFF:
1015 {
1016 if ( nextSReloc->r_type() != GENERIC_RELOC_PAIR ) {
1017 printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
1018 break;
1019 }
1020 srcAddr = sect->addr() + sreloc->r_address();
1021 uint32_t toAddr = sreloc->r_value();
1022 uint32_t fromAddr = nextSReloc->r_value();
1023 src = findAtomCoveringOffset(srcAddr);
1024 Atom* to = findAtomCoveringOffset(toAddr);
1025 Atom* from = findAtomCoveringOffset(fromAddr);
1026 Reference::Kind kind = Reference::pointer32Difference;
1027 if ( sreloc->r_length() != 2 )
1028 throw "bad length for GENERIC_RELOC_SECTDIFF";
1029 src->addDifferenceReference(srcAddr - src->fOffset, kind, *to, toAddr - to->fOffset, *from, fromAddr - from->fOffset);
1030 }
1031 break;
1032 case GENERIC_RELOC_PAIR:
1033 // do nothing, already used via a look ahead
1034 break;
1035 #endif
1036 default:
1037 printf("unknown scattered relocation type %d\n", sreloc->r_type());
1038 }
1039
1040 }
1041 }
1042
1043
1044 void Reader::addFixUp(uint32_t srcAddr, uint32_t dstAddr, Reference::Kind kind, uint32_t picBaseAddr)
1045 {
1046 Atom* src = findAtomCoveringOffset(srcAddr);
1047 Atom* dst = findAtomCoveringOffset(dstAddr);
1048 src->addReference(srcAddr - src->fOffset, kind, *dst, dstAddr - dst->fOffset, picBaseAddr - src->fOffset);
1049 }
1050
1051 Atom* Reader::findAtomCoveringOffset(uint32_t offset)
1052 {
1053 #if 1
1054 // binary search of sorted atoms
1055 Atom** base = &fAtoms[0];
1056 for (uint32_t n = fAtoms.size(); n > 0; n /= 2) {
1057 Atom** pivot = &base[n/2];
1058 Atom* pivotAtom = *pivot;
1059 if ( pivotAtom->fOffset <= offset ) {
1060 if ( offset < (pivotAtom->fOffset + pivotAtom->fSize) )
1061 return pivotAtom;
1062 // key > pivot
1063 // move base to symbol after pivot
1064 base = &pivot[1];
1065 --n;
1066 }
1067 else {
1068 // key < pivot
1069 // keep same base
1070 }
1071 }
1072 // possible that last atom is zero length
1073 Atom* lastAtom = fAtoms.back();
1074 if ( (lastAtom->fOffset == offset) && (lastAtom->fSize == 0) )
1075 return lastAtom;
1076 #else
1077 const uint32_t atomCount = fAtoms.size();
1078 for (uint32_t i=0; i < atomCount; ++i) {
1079 Atom* atom = fAtoms[i];
1080 if ( (atom->fOffset <= offset) && (offset < (atom->fOffset + atom->fSize)) )
1081 return atom;
1082 }
1083 #endif
1084 throwf("address 0x%08X is not in any atom", offset);
1085 }
1086
1087 uint32_t Reader::findAtomIndex(const Atom& atom)
1088 {
1089 const Atom* target = &atom;
1090 const uint32_t atomCount = fAtoms.size();
1091 for (uint32_t i=0; i < atomCount; ++i) {
1092 Atom* anAtom = fAtoms[i];
1093 if ( anAtom == target )
1094 return i;
1095 }
1096 return 0xffffffff;
1097 }
1098
1099 static void insertOffset(std::set<uint32_t>& offsets, uint32_t value)
1100 {
1101 //fprintf(stderr, "cleave point at 0x%08X\n", value);
1102 offsets.insert(value);
1103 }
1104
1105 void Reader::insertOffsetIfNotText(std::set<uint32_t>& offsets, uint32_t value)
1106 {
1107 const macho_section* sect = findSectionCoveringOffset(value);
1108 if ( (sect == NULL) || (strcmp(sect->segname(),"__TEXT") != 0) || (strncmp(sect->sectname(),"__text", 6) != 0) ) {
1109 offsets.insert(value);
1110 }
1111 }
1112
1113 void Reader::insertOffsetIfText(std::set<uint32_t>& offsets, uint32_t value)
1114 {
1115 const macho_section* sect = findSectionCoveringOffset(value);
1116 if ( (sect != NULL) && (strcmp(sect->segname(),"__TEXT") == 0) && (strncmp(sect->sectname(),"__text", 6) == 0) ) {
1117 //fprintf(stderr, "don't cleave point at 0x%08X\n", value);
1118 offsets.insert(value);
1119 }
1120 }
1121
1122 const macho_section* Reader::findSectionCoveringOffset(uint32_t offset)
1123 {
1124 const macho_section* const sectionsStart = (macho_section*)((char*)fSegment + sizeof(macho_segment_command));
1125 const macho_section* const sectionsEnd = &sectionsStart[fSegment->nsects()];
1126 for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1127 if ( (sect->addr() <= offset) && (offset < (sect->addr() + sect->size())) )
1128 return sect;
1129 }
1130 return NULL;
1131 }
1132
1133
1134 void Reader::buildOffsetsSet(const macho_relocation_info* reloc, const macho_section* sect, std::set<uint32_t>& cleavePoints, std::set<uint32_t>& dontCleavePoints)
1135 {
1136 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
1137 uint32_t targetAddr;
1138 #endif
1139 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
1140 uint32_t* fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
1141 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
1142 uint32_t instruction;
1143 #endif
1144 switch ( reloc->r_type() ) {
1145 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
1146 case PPC_RELOC_BR14:
1147 // do nothing. local branch should not cleave
1148 break;
1149 case PPC_RELOC_BR24:
1150 {
1151 if ( ! reloc->r_extern() ) {
1152 instruction = OSSwapBigToHostInt32(*fixUpPtr);
1153 if ( (instruction & 0x4C000000) == 0x48000000 ) {
1154 int32_t displacement = (instruction & 0x03FFFFFC);
1155 if ( (displacement & 0x02000000) != 0 )
1156 displacement |= 0xFC000000;
1157 //cleavePoints.insert(reloc->r_address() + displacement);
1158 insertOffset(cleavePoints, sect->addr() + reloc->r_address() + displacement);
1159 }
1160 }
1161 }
1162 break;
1163 case PPC_RELOC_PAIR:
1164 // skip, processed by a look ahead
1165 break;
1166 case PPC_RELOC_LO16:
1167 {
1168 const macho_relocation_info* nextReloc = &reloc[1];
1169 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
1170 printf("PPC_RELOC_LO16 missing following pair\n");
1171 break;
1172 }
1173 if ( ! reloc->r_extern() ) {
1174 instruction = OSSwapBigToHostInt32(*fixUpPtr);
1175 targetAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFF);
1176 //cleavePoints.insert(targetAddr);
1177 insertOffset(cleavePoints, (targetAddr));
1178 }
1179 }
1180 break;
1181 case PPC_RELOC_LO14:
1182 {
1183 const macho_relocation_info* nextReloc = &reloc[1];
1184 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
1185 printf("PPC_RELOC_LO14 missing following pair\n");
1186 break;
1187 }
1188 if ( ! reloc->r_extern() ) {
1189 instruction = OSSwapBigToHostInt32(*fixUpPtr);
1190 targetAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC);
1191 //cleavePoints.insert(targetAddr);
1192 insertOffset(cleavePoints, (targetAddr));
1193 }
1194 }
1195 break;
1196 case PPC_RELOC_HI16:
1197 {
1198 const macho_relocation_info* nextReloc = &reloc[1];
1199 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
1200 printf("PPC_RELOC_HI16 missing following pair\n");
1201 break;
1202 }
1203 if ( ! reloc->r_extern() ) {
1204 instruction = OSSwapBigToHostInt32(*fixUpPtr);
1205 targetAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
1206 //cleavePoints.insert(targetAddr);
1207 insertOffset(cleavePoints, targetAddr);
1208 }
1209 }
1210 break;
1211 case PPC_RELOC_HA16:
1212 {
1213 const macho_relocation_info* nextReloc = &reloc[1];
1214 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
1215 printf("PPC_RELOC_HA16 missing following pair\n");
1216 break;
1217 }
1218 if ( ! reloc->r_extern() ) {
1219 instruction = OSSwapBigToHostInt32(*fixUpPtr);
1220 int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF);
1221 targetAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
1222 //cleavePoints.insert(targetAddr);
1223 insertOffset(cleavePoints, targetAddr);
1224 }
1225 }
1226 break;
1227 case PPC_RELOC_JBSR:
1228 // ignore for now
1229 break;
1230 #endif
1231 case GENERIC_RELOC_VANILLA:
1232 {
1233 #if defined(ARCH_PPC64)
1234 if ( reloc->r_length() != 3 )
1235 throw "vanilla pointer relocation found that is not 8-bytes";
1236 #elif defined(ARCH_PPC) || defined(ARCH_I386)
1237 if ( reloc->r_length() != 2 )
1238 throw "vanilla pointer relocation found that is not 4-bytes";
1239 #endif
1240 //fprintf(stderr, "addr=0x%08X, pcrel=%d, len=%d, extern=%d, type=%d\n", reloc->r_address(), reloc->r_pcrel(), reloc->r_length(), reloc->r_extern(), reloc->r_type());
1241 if ( !reloc->r_extern() ) {
1242 macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
1243 #if defined(ARCH_I386)
1244 // i386 stubs have internal relocs that should not cause a cleave
1245 if ( (sect->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS )
1246 break;
1247 #endif
1248 if ( reloc->r_pcrel() )
1249 pointerValue += reloc->r_address() + sect->addr() + sizeof(macho_uintptr_t);
1250 // a pointer into code does not cleave the code (gcc always pointers to labels)
1251 insertOffsetIfNotText(cleavePoints, pointerValue);
1252 }
1253 }
1254 break;
1255 default:
1256 printf("unknown relocation type %d\n", reloc->r_type());
1257 }
1258 }
1259 else {
1260 const macho_scattered_relocation_info* sreloc = (macho_scattered_relocation_info*)reloc;
1261 switch (sreloc->r_type()) {
1262 case GENERIC_RELOC_VANILLA:
1263 insertOffset(cleavePoints, sreloc->r_value());
1264 break;
1265 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
1266 case PPC_RELOC_BR24:
1267 insertOffset(cleavePoints, sreloc->r_value());
1268 break;
1269 case PPC_RELOC_HA16:
1270 case PPC_RELOC_HI16:
1271 case PPC_RELOC_LO16:
1272 case PPC_RELOC_LO14:
1273 case PPC_RELOC_LO16_SECTDIFF:
1274 case PPC_RELOC_LO14_SECTDIFF:
1275 case PPC_RELOC_HA16_SECTDIFF:
1276 case PPC_RELOC_HI16_SECTDIFF:
1277 //cleavePoints.insert(sreloc->r_value());
1278 insertOffset(cleavePoints, sreloc->r_value());
1279 insertOffsetIfText(dontCleavePoints, sreloc->r_value());
1280 break;
1281 case PPC_RELOC_SECTDIFF:
1282 case PPC_RELOC_LOCAL_SECTDIFF:
1283 // these do not cleave up a .o file
1284 // a SECTDIFF in __TEXT probably means a jump table, and should prevent a cleave
1285 {
1286 const macho_scattered_relocation_info* nextReloc = &sreloc[1];
1287 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
1288 printf("PPC_RELOC_SECTDIFF missing following pair\n");
1289 break;
1290 }
1291 insertOffsetIfText(dontCleavePoints, sreloc->r_value());
1292 insertOffsetIfText(dontCleavePoints, nextReloc->r_value());
1293 }
1294 break;
1295 case PPC_RELOC_PAIR:
1296 // do nothing, already used via a look ahead
1297 break;
1298 #endif
1299 #if defined(ARCH_I386)
1300 case GENERIC_RELOC_SECTDIFF:
1301 case GENERIC_RELOC_LOCAL_SECTDIFF:
1302 // these do not cleave up a .o file
1303 // a SECTDIFF in __TEXT probably means a jump table, and should prevent a cleave
1304 {
1305 const macho_scattered_relocation_info* nextReloc = &sreloc[1];
1306 if ( nextReloc->r_type() != GENERIC_RELOC_PAIR ) {
1307 printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
1308 break;
1309 }
1310 insertOffsetIfText(dontCleavePoints, sreloc->r_value());
1311 insertOffsetIfText(dontCleavePoints, nextReloc->r_value());
1312 }
1313 break;
1314 case GENERIC_RELOC_PAIR:
1315 // do nothing, already used via a look ahead
1316 break;
1317 #endif
1318 default:
1319 printf("unknown relocation type %d\n", sreloc->r_type());
1320 }
1321
1322 }
1323 }
1324
1325
1326 Segment* Reader::makeSegmentFromSection(const macho_section* sect)
1327 {
1328 // make segment object if one does not already exist
1329 const uint32_t segmentCount = fSegments.size();
1330 for (uint32_t i=0; i < segmentCount; ++i) {
1331 Segment* seg = fSegments[i];
1332 if ( strcmp(sect->segname(), seg->getName()) == 0 )
1333 return seg;
1334 }
1335 Segment* seg = new Segment(sect);
1336 fSegments.push_back(seg);
1337 return seg;
1338 }
1339
1340 macho_uintptr_t Reader::commonsOffset()
1341 {
1342 return fSegment->vmsize();
1343 }
1344
1345 const char* Reader::getPath()
1346 {
1347 return fPath;
1348 }
1349
1350 std::vector<class ObjectFile::Atom*>& Reader::getAtoms()
1351 {
1352 return (std::vector<class ObjectFile::Atom*>&)(fAtoms);
1353 }
1354
1355 std::vector<class ObjectFile::Atom*>* Reader::getJustInTimeAtomsFor(const char* name)
1356 {
1357 // object files have no just-in-time atoms
1358 return NULL;
1359 }
1360
1361
1362 std::vector<ObjectFile::StabsInfo>* Reader::getStabsDebugInfo()
1363 {
1364 if ( fNonAtomStabsCount == 0 )
1365 return NULL;
1366
1367 std::vector<ObjectFile::StabsInfo>* stabs = new std::vector<ObjectFile::StabsInfo>();
1368 stabs->reserve(fNonAtomStabsCount);
1369
1370 for (uint32_t i=0; i < fNonAtomStabsCount; ++i) {
1371 const macho_nlist* sym = &fSymbols[fNonAtomStabsStartIndex+i];
1372 if ( (sym->n_type() & N_STAB) != 0 ) {
1373 ObjectFile::StabsInfo stab;
1374 stab.atomOffset = sym->n_value();
1375 stab.string = &fStrings[sym->n_strx()];
1376 stab.type = sym->n_type();
1377 stab.other = sym->n_sect();
1378 stab.desc = sym->n_desc();
1379 // for N_SO n_value is offset of first atom, but our gdb ignores this, so we omit that calculation
1380 if ( stab.type == N_SO )
1381 stab.atomOffset = 0;
1382 stabs->push_back(stab);
1383 }
1384 }
1385
1386 // add any extra N_LSYM's not at start of symbol table
1387 for (std::vector<uint32_t>::iterator it=fNonAtomExtras.begin(); it != fNonAtomExtras.end(); ++it) {
1388 const macho_nlist* sym = &fSymbols[*it];
1389 ObjectFile::StabsInfo stab;
1390 stab.atomOffset = sym->n_value();
1391 stab.string = &fStrings[sym->n_strx()];
1392 stab.type = sym->n_type();
1393 stab.other = sym->n_sect();
1394 stab.desc = sym->n_desc();
1395 stabs->push_back(stab);
1396 }
1397
1398 return stabs;
1399 }
1400
1401 void Reader::deadStub(Atom& target)
1402 {
1403 // remove stub
1404 fDeadAtoms.insert(&target);
1405
1406 // remove lazy pointer
1407 const int stubNameLen = strlen(target.fSynthesizedName);
1408 char lazyName[stubNameLen+8];
1409 strcpy(lazyName, target.fSynthesizedName);
1410 strcpy(&lazyName[stubNameLen-5], "$lazy_ptr");
1411 const uint32_t atomCount = fAtoms.size();
1412 for (uint32_t i=1; i < atomCount; ++i) {
1413 Atom* atom = fAtoms[i];
1414 if ( (atom->fSynthesizedName != NULL) && (strcmp(atom->fSynthesizedName, lazyName) == 0) ) {
1415 fDeadAtoms.insert(atom);
1416 break;
1417 }
1418 }
1419 }
1420
1421
1422 void Reader::addCallSiteReference(Atom& src, uint32_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint32_t picBaseOffset, uint32_t offsetInTargetAtom)
1423 {
1424 // the compiler some times produces stub to static functions and then calls the stubs
1425 // we need to skip the stub if a static function exists with the same name and remove the stub
1426 if ( target.isLazyStub() ) {
1427 const macho_section* section = target.fSection;
1428 uint32_t index = (target.fOffset - section->addr()) / section->reserved2();
1429 uint32_t indirectTableIndex = section->reserved1() + index;
1430 uint32_t symbolIndex = ENDIAN_READ32(fIndirectTable[indirectTableIndex]);
1431 if ( (symbolIndex & INDIRECT_SYMBOL_LOCAL) == 0 ) {
1432 const macho_nlist* sym = &fSymbols[symbolIndex];
1433 if ( (sym->n_value() != 0) && ((sym->n_type() & N_EXT) == 0) ) {
1434 Atom* betterTarget = this->findAtomCoveringOffset(sym->n_value());
1435 if ( (betterTarget != NULL) && (betterTarget->getScope() == ObjectFile::Atom::scopeTranslationUnit) ) {
1436 // use direct reference to static function
1437 src.addDirectReference(offsetInSrcAtom, kind, *betterTarget, offsetInTargetAtom, picBaseOffset);
1438
1439 // remove stub and lazy pointer
1440 this->deadStub(target);
1441 return;
1442 }
1443 }
1444 }
1445 }
1446
1447 // fall through to general case
1448 src.addReference(offsetInSrcAtom, kind, target, offsetInTargetAtom, picBaseOffset);
1449 }
1450
1451
1452 Atom::Atom(Reader& owner, const macho_nlist* symbol)
1453 : fOwner(owner), fSymbol(symbol), fOffset(0), fSize(0), fSection(NULL), fSegment(NULL), fSynthesizedName(NULL),
1454 fStabsStartIndex(0), fStabsCount(0)
1455 {
1456 uint8_t type = symbol->n_type();
1457 if ( (type & N_EXT) == 0 )
1458 fScope = ObjectFile::Atom::scopeTranslationUnit;
1459 else if ( (type & N_PEXT) != 0 )
1460 fScope = ObjectFile::Atom::scopeLinkageUnit;
1461 else
1462 fScope = ObjectFile::Atom::scopeGlobal;
1463 if ( (type & N_TYPE) == N_SECT ) {
1464 // real definition
1465 const macho_section* sections = (macho_section*)((char*)fOwner.fSegment + sizeof(macho_segment_command));
1466 fSection = &sections[fSymbol->n_sect()-1];
1467 fSegment = owner.makeSegmentFromSection(fSection);
1468 fOffset = fSymbol->n_value();
1469 uint8_t type = fSection->flags() & SECTION_TYPE;
1470 switch ( type ) {
1471 case S_LAZY_SYMBOL_POINTERS:
1472 case S_NON_LAZY_SYMBOL_POINTERS:
1473 {
1474 // get target name out of indirect symbol table
1475 uint32_t index = (fOffset - fSection->addr()) / sizeof(macho_uintptr_t);
1476 index += fSection->reserved1();
1477 uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]);
1478 uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx();
1479 const char* name = &fOwner.fStrings[strOffset];
1480 Reference* ref = this->addByNameReference(0, Reference::pointer, name, 0, 0);
1481 if ( type == S_LAZY_SYMBOL_POINTERS ) {
1482 ref->setLazy(true);
1483 }
1484 }
1485 break;
1486 }
1487 }
1488 else if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) {
1489 // tentative definition
1490 fSize = symbol->n_value();
1491 fSection = getCommonsSection();
1492 fSegment = owner.makeSegmentFromSection(fSection);
1493 fOffset = owner.commonsOffset();
1494 }
1495 else {
1496 printf("unknown symbol type: %d\n", type);
1497 }
1498 }
1499
1500 Atom::Atom(Reader& owner, uint32_t offset)
1501 : fOwner(owner), fSymbol(NULL), fOffset(offset), fSize(0), fSection(NULL), fSegment(NULL), fSynthesizedName(NULL),
1502 fStabsStartIndex(0), fStabsCount(0)
1503 {
1504 fSection = findSectionFromOffset(offset);
1505 fScope = ObjectFile::Atom::scopeLinkageUnit;
1506 fSegment = owner.makeSegmentFromSection(fSection);
1507 uint8_t type = fSection->flags() & SECTION_TYPE;
1508 switch ( type ) {
1509 case S_SYMBOL_STUBS:
1510 {
1511 uint32_t index = (offset - fSection->addr()) / fSection->reserved2();
1512 index += fSection->reserved1();
1513 uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]);
1514 uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx();
1515 const char* name = &fOwner.fStrings[strOffset];
1516 char* str = new char[strlen(name)+8];
1517 strcpy(str, name);
1518 strcat(str, "$stub");
1519 fSynthesizedName = str;
1520 }
1521 break;
1522 case S_LAZY_SYMBOL_POINTERS:
1523 case S_NON_LAZY_SYMBOL_POINTERS:
1524 {
1525 uint32_t index = (offset - fSection->addr()) / sizeof(macho_uintptr_t);
1526 index += fSection->reserved1();
1527 uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]);
1528 uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx();
1529 const char* name = &fOwner.fStrings[strOffset];
1530 char* str = new char[strlen(name)+16];
1531 strcpy(str, name);
1532 if ( type == S_LAZY_SYMBOL_POINTERS )
1533 strcat(str, "$lazy_ptr");
1534 else
1535 strcat(str, "$non_lazy_ptr");
1536 fSynthesizedName = str;
1537 Reference* ref = this->addByNameReference(0, Reference::pointer, name, 0, 0);
1538 if ( type == S_LAZY_SYMBOL_POINTERS ) {
1539 ref->setLazy(true);
1540 }
1541 const macho_nlist* sym = &fOwner.fSymbols[symbolIndex];
1542 if ( (sym->n_type() & N_TYPE) == N_UNDF ) {
1543 if ( (sym->n_desc() & N_WEAK_REF) != 0 )
1544 ref->setWeak(true);
1545 }
1546 }
1547 break;
1548 }
1549 }
1550
1551
1552 Atom::~Atom()
1553 {
1554 }
1555
1556 macho_section Atom::fgCommonsSection;
1557
1558
1559 bool Atom::isLazyStub()
1560 {
1561 return ( (fSection->flags() & SECTION_TYPE) == S_SYMBOL_STUBS);
1562 }
1563
1564 const macho_section* Atom::getCommonsSection() {
1565 if ( strcmp(fgCommonsSection.sectname(), "__common") != 0 ) {
1566 fgCommonsSection.set_sectname("__common");
1567 fgCommonsSection.set_segname("__DATA");
1568 fgCommonsSection.set_flags(S_ZEROFILL);
1569 }
1570 return &fgCommonsSection;
1571 }
1572
1573 ObjectFile::Reader* Atom::getFile() const
1574 {
1575 return &fOwner;
1576 }
1577
1578
1579 const char* Atom::getName() const
1580 {
1581 if ( fSymbol != NULL )
1582 return &fOwner.fStrings[fSymbol->n_strx()];
1583 else
1584 return fSynthesizedName;
1585 }
1586
1587 const char* Atom::getDisplayName() const
1588 {
1589 if ( fSymbol != NULL )
1590 return &fOwner.fStrings[fSymbol->n_strx()];
1591
1592 if ( fSynthesizedName != NULL )
1593 return fSynthesizedName;
1594
1595 static char temp[32];
1596 sprintf(temp, "atom #%u", fOwner.findAtomIndex(*this));
1597 return temp;
1598 }
1599
1600 ObjectFile::Atom::Scope Atom::getScope() const
1601 {
1602 return fScope;
1603 }
1604
1605 void Atom::setScope(ObjectFile::Atom::Scope newScope)
1606 {
1607 fScope = newScope;
1608 }
1609
1610
1611 bool Atom::isWeakDefinition() const
1612 {
1613 if ( isTentativeDefinition() )
1614 return true;
1615 if ( fSymbol != NULL )
1616 return ( (fSymbol->n_desc() & N_WEAK_DEF) != 0 );
1617 uint8_t type = fSection->flags() & SECTION_TYPE;
1618 switch ( type ) {
1619 case S_SYMBOL_STUBS:
1620 case S_LAZY_SYMBOL_POINTERS:
1621 case S_NON_LAZY_SYMBOL_POINTERS:
1622 return true;
1623 }
1624 return false;
1625 }
1626
1627 bool Atom::isTentativeDefinition() const
1628 {
1629 return (fSection == &fgCommonsSection);
1630 }
1631
1632 bool Atom::isCoalesableByName() const
1633 {
1634 uint8_t type = fSection->flags() & SECTION_TYPE;
1635 switch ( type ) {
1636 case S_SYMBOL_STUBS:
1637 case S_COALESCED:
1638 return true;
1639 };
1640 if ( isTentativeDefinition() )
1641 return true;
1642 return false;
1643 }
1644
1645 bool Atom::isCoalesableByValue() const
1646 {
1647 uint8_t type = fSection->flags() & SECTION_TYPE;
1648 switch ( type ) {
1649 case S_CSTRING_LITERALS:
1650 case S_4BYTE_LITERALS:
1651 case S_8BYTE_LITERALS:
1652 return true;
1653 };
1654 return false;
1655 }
1656
1657 bool Atom::isZeroFill() const
1658 {
1659 return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL);
1660 }
1661
1662 bool Atom::dontDeadStrip() const
1663 {
1664 if ( fSymbol != NULL )
1665 return ( (fSymbol->n_desc() & N_NO_DEAD_STRIP) != 0 );
1666 return false;
1667 }
1668
1669
1670 bool Atom::dontStripName() const
1671 {
1672 if ( fSymbol != NULL )
1673 return ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0 );
1674 return false;
1675 }
1676
1677 bool Atom::isImportProxy() const
1678 {
1679 return false;
1680 }
1681
1682
1683 uint64_t Atom::getSize() const
1684 {
1685 //return fOffset;
1686 return fSize;
1687 }
1688
1689
1690 std::vector<ObjectFile::Reference*>& Atom::getReferences() const
1691 {
1692 return (std::vector<ObjectFile::Reference*>&)(fReferences);
1693 }
1694
1695 bool Atom::mustRemainInSection() const
1696 {
1697 return true;
1698 }
1699
1700 const char* Atom::getSectionName() const
1701 {
1702 if ( strlen(fSection->sectname()) > 15 ) {
1703 static char temp[18];
1704 strncpy(temp, fSection->sectname(), 16);
1705 temp[17] = '\0';
1706 return temp;
1707 }
1708 return fSection->sectname();
1709 }
1710
1711 Segment& Atom::getSegment() const
1712 {
1713 return *fSegment;
1714 }
1715
1716 bool Atom::requiresFollowOnAtom() const
1717 {
1718 // requires follow-on if built with old compiler and not the last atom
1719 if ( (fOwner.fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0) {
1720 if ( fOwner.findAtomIndex(*this) < (fOwner.fAtoms.size()-1) )
1721 return true;
1722 }
1723 return false;
1724 }
1725
1726 ObjectFile::Atom& Atom::getFollowOnAtom() const
1727 {
1728 uint32_t myIndex = fOwner.findAtomIndex(*this);
1729 return *fOwner.fAtoms[myIndex+1];
1730 }
1731
1732 std::vector<ObjectFile::StabsInfo>* Atom::getStabsDebugInfo() const
1733 {
1734 if ( fStabsCount == 0 )
1735 return NULL;
1736
1737 std::vector<ObjectFile::StabsInfo>* stabs = new std::vector<ObjectFile::StabsInfo>();
1738 stabs->reserve(fStabsCount);
1739
1740 for (uint32_t i=0; i < fStabsCount; ++i) {
1741 const macho_nlist* sym = &fOwner.fSymbols[fStabsStartIndex+i];
1742 if ( (sym->n_type() & N_STAB) != 0 ) {
1743 ObjectFile::StabsInfo stab;
1744 stab.atomOffset = sym->n_value();
1745 stab.string = &fOwner.fStrings[sym->n_strx()];
1746 stab.type = sym->n_type();
1747 stab.other = sym->n_sect();
1748 stab.desc = sym->n_desc();
1749 switch ( stab.type ) {
1750 case N_FUN:
1751 if ( stab.other == 0 )
1752 break;
1753 // end of function N_FUN has size (not address) so should not be adjusted
1754 // fall through
1755 case N_BNSYM:
1756 case N_ENSYM:
1757 case N_LBRAC:
1758 case N_RBRAC:
1759 case N_SLINE:
1760 case N_STSYM:
1761 case N_LCSYM:
1762 // all these stab types need their value changed from an absolute address to the atom offset
1763 stab.atomOffset -= fOffset;
1764 break;
1765 }
1766 stabs->push_back(stab);
1767 }
1768 }
1769
1770 return stabs;
1771 }
1772
1773 uint8_t Atom::getAlignment() const
1774 {
1775 // mach-o file format has no alignment information for atoms - just whole sections
1776 if ( fSection != NULL ) {
1777 if ( isTentativeDefinition() ) {
1778 // common symbols align to their size
1779 // that is, a 4-byte common aligns to 4-bytes
1780 // to be safe, odd size commons align to the next power-of-2 size
1781 uint8_t alignment = (uint8_t)ceil(log2(this->getSize()));
1782 // limit alignment of extremely large commons to 2^15 bytes (8-page)
1783 if ( alignment < 15 )
1784 return alignment;
1785 else
1786 return 15;
1787 }
1788 else {
1789 // so we assume every atom requires the same alignment as the whole section
1790 return fSection->align();
1791 }
1792 }
1793 else {
1794 return 2;
1795 }
1796 }
1797
1798 void Atom::copyRawContent(uint8_t buffer[]) const
1799 {
1800 // copy base bytes
1801 if ( isZeroFill() )
1802 bzero(buffer, fSize);
1803 else {
1804 uint32_t fileOffset = fSection->offset() - fSection->addr() + fOffset;
1805 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
1806 }
1807 }
1808
1809 void Atom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
1810 {
1811 const uint32_t referencesCount = fReferences.size();
1812
1813 // skip copy if no fix-ups
1814 if ( referencesCount == 0 ) {
1815 uint32_t fileOffset = fSection->offset() - fSection->addr() + fOffset;
1816 writer.write(0, (char*)(fOwner.fHeader)+fileOffset, fSize);
1817 return;
1818 }
1819
1820 // copy base bytes
1821 uint8_t buffer[this->getSize()];
1822 this->copyRawContent(buffer);
1823
1824 // apply any fix-ups
1825 for (uint32_t i=0; i < referencesCount; ++i) {
1826 Reference* ref = fReferences[i];
1827 uint32_t offset = ref->getFixUpOffset();
1828 uint32_t* instructionPtr = (uint32_t*)&buffer[offset];
1829 ObjectFile::Atom& target = ref->getTarget();
1830 if ( &target == NULL ) {
1831 if ( finalLinkedImage )
1832 throw "target not found";
1833 else
1834 continue;
1835 }
1836 uint32_t instruction;
1837 uint32_t newInstruction;
1838 switch ( ref->getKind() ) {
1839 case Reference::noFixUp:
1840 break;
1841 case Reference::pointer:
1842 {
1843 //fprintf(stderr, "writeContent: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
1844 if ( ref->isLazyReference() && finalLinkedImage ) {
1845 // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
1846 *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getFromTarget().getAddress());
1847 }
1848 else if ( target.isImportProxy() ) {
1849 // external realocation ==> pointer contains addend
1850 *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getTargetOffset());
1851 }
1852 else {
1853 // internal relocation
1854 if ( finalLinkedImage || (strcmp(target.getSectionName(), "__common") != 0) ) {
1855 // pointer contains target address
1856 //printf("Atom::writeContent() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
1857 *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(target.getAddress() + ref->getTargetOffset());
1858 }
1859 else {
1860 // pointer contains addend
1861 *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getTargetOffset());
1862 }
1863 }
1864 }
1865 break;
1866 case Reference::ppcFixupBranch24:
1867 {
1868 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
1869 int64_t displacement = (target.getAddress() + ref->getTargetOffset() ) - (this->getAddress() + offset);
1870 if ( !finalLinkedImage && target.isImportProxy() ) {
1871 // doing "ld -r" to an external symbol
1872 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
1873 displacement -= target.getAddress();
1874 }
1875 else {
1876 const int64_t bl_eightMegLimit = 0x00FFFFFF;
1877 if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
1878 //fprintf(stderr, "bl out of range (%lld max is +/-16M) from %s in %s to %s in %s\n", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
1879 throwf("bl out of range (%lld max is +/-16M) from %s in %s to %s in %s", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
1880 }
1881 }
1882 instruction = OSReadBigInt32(instructionPtr, 0);
1883 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
1884 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
1885 OSWriteBigInt32(instructionPtr, 0, newInstruction);
1886 }
1887 break;
1888 case Reference::ppcFixupBranch14:
1889 break;
1890 case Reference::ppcFixupPicBaseLow16:
1891 {
1892 uint64_t targetAddr = target.getAddress() + ref->getTargetOffset();
1893 uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset();
1894 int64_t displacement = targetAddr - picBaseAddr;
1895 const int64_t picbase_twoGigLimit = 0x80000000;
1896 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
1897 throw "32-bit pic-base out of range";
1898 uint16_t instructionLowHalf = (displacement & 0xFFFF);
1899 instruction = OSReadBigInt32(instructionPtr, 0);
1900 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
1901 OSWriteBigInt32(instructionPtr, 0, newInstruction);
1902 }
1903 break;
1904 case Reference::ppcFixupPicBaseLow14:
1905 {
1906 uint64_t targetAddr = target.getAddress() + ref->getTargetOffset();
1907 uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset();
1908 int64_t displacement = targetAddr - picBaseAddr;
1909 const int64_t picbase_twoGigLimit = 0x80000000;
1910 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
1911 throw "32-bit pic-base out of range";
1912 uint16_t instructionLowHalf = (displacement & 0xFFFF);
1913 if ( (instructionLowHalf & 0x3) != 0 )
1914 throw "bad address for lo14 instruction fix-up";
1915 instruction = OSReadBigInt32(instructionPtr, 0);
1916 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
1917 OSWriteBigInt32(instructionPtr, 0, newInstruction);
1918 }
1919 break;
1920 case Reference::ppcFixupPicBaseHigh16:
1921 {
1922 uint64_t targetAddr = target.getAddress() + ref->getTargetOffset();
1923 uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset();
1924 int64_t displacement = targetAddr - picBaseAddr;
1925 const int64_t picbase_twoGigLimit = 0x80000000;
1926 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
1927 throw "32-bit pic-base out of range";
1928 uint16_t instructionLowHalf = displacement >> 16;
1929 if ( (displacement & 0x00008000) != 0 )
1930 ++instructionLowHalf;
1931 instruction = OSReadBigInt32(instructionPtr, 0);
1932 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
1933 OSWriteBigInt32(instructionPtr, 0, newInstruction);
1934 }
1935 break;
1936 case Reference::ppcFixupAbsLow16:
1937 {
1938 int64_t addr = target.getAddress() + ref->getTargetOffset();
1939 if ( !finalLinkedImage && target.isImportProxy() )
1940 addr -= target.getAddress() ;
1941 uint16_t instructionLowHalf = (addr & 0xFFFF);
1942 instruction = OSReadBigInt32(instructionPtr, 0);
1943 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
1944 OSWriteBigInt32(instructionPtr, 0, newInstruction);
1945 }
1946 break;
1947 case Reference::ppcFixupAbsLow14:
1948 {
1949 int64_t addr = target.getAddress() + ref->getTargetOffset();
1950 if ( !finalLinkedImage && target.isImportProxy() )
1951 addr -= target.getAddress() ;
1952 uint16_t instructionLowHalf = (addr & 0xFFFF);
1953 if ( (instructionLowHalf & 0x3) != 0 )
1954 throw "bad address for lo14 instruction fix-up";
1955 instruction = OSReadBigInt32(instructionPtr, 0);
1956 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
1957 OSWriteBigInt32(instructionPtr, 0, newInstruction);
1958 }
1959 break;
1960 case Reference::ppcFixupAbsHigh16:
1961 {
1962 int64_t addr = target.getAddress() + ref->getTargetOffset();
1963 if ( !finalLinkedImage && target.isImportProxy() )
1964 addr -= target.getAddress() ;
1965 uint16_t hi16 = (addr >> 16);
1966 instruction = OSReadBigInt32(instructionPtr, 0);
1967 newInstruction = (instruction & 0xFFFF0000) | hi16;
1968 OSWriteBigInt32(instructionPtr, 0, newInstruction);
1969 }
1970 break;
1971 case Reference::ppcFixupAbsHigh16AddLow:
1972 {
1973 int64_t addr = target.getAddress() + ref->getTargetOffset();
1974 if ( !finalLinkedImage && target.isImportProxy() )
1975 addr -= target.getAddress() ;
1976 if ( addr & 0x00008000 )
1977 addr += 0x00010000;
1978 instruction = OSReadBigInt32(instructionPtr, 0);
1979 newInstruction = (instruction & 0xFFFF0000) | (addr >> 16);
1980 OSWriteBigInt32(instructionPtr, 0, newInstruction);
1981 }
1982 break;
1983 case Reference::pointer32Difference:
1984 ENDIAN_WRITE32(*instructionPtr, target.getAddress() + ref->getTargetOffset() - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()));
1985 break;
1986 case Reference::pointer64Difference:
1987 *((uint64_t*)instructionPtr) = ENDIAN_SWAP64(target.getAddress() + ref->getTargetOffset() - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()));
1988 break;
1989 case Reference::x86FixupBranch32:
1990 {
1991 int64_t displacement = target.getAddress() - (this->getAddress() + offset);
1992 if ( target.isImportProxy() ) {
1993 displacement = 0;
1994 }
1995 else {
1996 const int64_t bl_twoGigLimit = 0x7FFFFFFF;
1997 if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_twoGigLimit)) ) {
1998 //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());
1999 throw "call out of range";
2000 }
2001 }
2002 OSWriteLittleInt32(instructionPtr, 0, (int32_t)displacement);
2003 }
2004 break;
2005 }
2006 }
2007
2008 // write out
2009 writer.write(0, buffer, getSize());
2010 }
2011
2012
2013
2014 const macho_section* Atom::findSectionFromOffset(uint32_t offset)
2015 {
2016 const macho_section* const sectionsStart = (const macho_section*)( (char*)fOwner.fSegment + sizeof(macho_segment_command) );
2017 const macho_section* const sectionsEnd = &sectionsStart[fOwner.fSegment->nsects()];
2018 for (const macho_section* s = sectionsStart; s < sectionsEnd; ++s) {
2019 if ( (s->addr() <= offset) && (offset < (s->addr()+s->size())) )
2020 return s;
2021 }
2022 throwf("address 0x%08X is not in any section", offset);
2023 }
2024
2025 void Atom::setSize(macho_uintptr_t size)
2026 {
2027 fSize = size;
2028 }
2029
2030
2031 void Atom::setFollowOnAtom(Atom&)
2032 {
2033
2034 }
2035
2036 Reference* Atom::addReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
2037 {
2038 if ( (target.getScope() != ObjectFile::Atom::scopeTranslationUnit) && ((target.fSymbol != NULL) || (target.fSynthesizedName != NULL)) )
2039 return this->addByNameReference(offsetInSrcAtom, kind, target.getName(), offsetInTarget, offsetInFromTarget);
2040 else
2041 return this->addDirectReference(offsetInSrcAtom, kind, target, offsetInTarget, offsetInFromTarget);
2042 }
2043
2044
2045 Reference* Atom::addDirectReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
2046 {
2047 Reference* ref = new Reference(offsetInSrcAtom, kind, target, offsetInTarget, offsetInFromTarget);
2048 // in rare cases, there may already be a by-name reference to the same atom. If so, replace with this direct reference
2049 for (std::vector<Reference*>::iterator it=fReferences.begin(); it != fReferences.end(); it++) {
2050 ObjectFile::Reference* aRef = *it;
2051 if ( (aRef->getFixUpOffset() == offsetInSrcAtom) && (aRef->getKind() == kind) ) {
2052 *it = ref;
2053 return ref;
2054 }
2055 }
2056
2057 // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
2058 fReferences.insert(fReferences.begin(), ref);
2059 return ref;
2060 }
2061
2062 Reference* Atom::addByNameReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
2063 {
2064 Reference* ref = new Reference(offsetInSrcAtom, kind, targetName, offsetInTarget, offsetInFromTarget);
2065 // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
2066 fReferences.insert(fReferences.begin(), ref);
2067 return ref;
2068 }
2069
2070 Reference* Atom::addDifferenceReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, Atom& fromTarget, uint64_t offsetInFromTarget)
2071 {
2072 Reference* ref = new Reference(offsetInSrcAtom, kind, target, offsetInTarget, fromTarget, offsetInFromTarget);
2073 // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
2074 fReferences.insert(fReferences.begin(), ref);
2075 return ref;
2076 }
2077
2078
2079 Segment::Segment(const macho_section* sect)
2080 : fSection(sect)
2081 {
2082 }
2083
2084 const char* Segment::getName() const
2085 {
2086 return fSection->segname();
2087 }
2088
2089 bool Segment::isContentReadable() const
2090 {
2091 return true;
2092 }
2093
2094 bool Segment::isContentWritable() const
2095 {
2096 if ( strcmp(fSection->segname(), "__DATA") == 0 )
2097 return true;
2098 if ( strcmp(fSection->segname(), "__OBJC") == 0 )
2099 return true;
2100 return false;
2101 }
2102
2103 bool Segment::isContentExecutable() const
2104 {
2105 return ( strcmp(fSection->segname(), "__TEXT") == 0 );
2106 }
2107
2108
2109 Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
2110 : fTarget(NULL), fFromTarget(NULL), fTargetName(targetName), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget),
2111 fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false)
2112 {
2113 }
2114
2115 Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
2116 : fTarget(&target), fFromTarget(NULL), fTargetName(NULL), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget),
2117 fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false)
2118 {
2119 }
2120
2121 Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, class Atom& fromTarget, uint64_t offsetInFromTarget)
2122 : fTarget(&target), fFromTarget(&fromTarget), fTargetName(NULL), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget),
2123 fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false)
2124 {
2125 // assure no direct references to something that might be coalesced
2126 if ( (target.isWeakDefinition() || target.isCoalesableByName()) && (target.getScope() != ObjectFile::Atom::scopeTranslationUnit) && (target.getName() != NULL) ) {
2127 //fprintf(stderr, "change TO direct reference to by-name: from %s to %s in %p\n", fromTarget.getDisplayName(), target.getName(), this);
2128 fTargetName = target.getName();
2129 fTarget = NULL;
2130 }
2131 // Note: We should also allow by-name from references, but many other chunks of code assume from targets are always direct//
2132 // if ( (fromTarget.isWeakDefinition() || fromTarget.isCoalesableByName()) && (fromTarget.getScope() != ObjectFile::Atom::scopeTranslationUnit) && (fromTarget.getName() != NULL)) {
2133 // fprintf(stderr, "change FROM direct reference to by-name: from %s to %s in %p\n", fromTarget.getDisplayName(), target.getName(), this);
2134 // fFromTargetName = fromTarget.getName();
2135 // fFromTarget = NULL;
2136 // }
2137 }
2138
2139
2140
2141 Reference::~Reference()
2142 {
2143 }
2144
2145 bool Reference::isTargetUnbound() const
2146 {
2147 return ( fTarget == NULL );
2148 }
2149
2150 bool Reference::isFromTargetUnbound() const
2151 {
2152 return ( fFromTarget == NULL );
2153 }
2154
2155 bool Reference::isWeakReference() const
2156 {
2157 return fWeak;
2158 }
2159
2160 bool Reference::requiresRuntimeFixUp(bool slideable) const
2161 {
2162 // This static linker only supports pure code (no code fixups are runtime)
2163 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
2164 // Only data can be fixed up, and the codegen assures only "pointers" need runtime fixups
2165 return ( (fKind == Reference::pointer) && (fTarget->isImportProxy() || fTarget->isWeakDefinition() || slideable) );
2166 #elif defined(ARCH_I386)
2167 // For i386, Reference::pointer is used for both data pointers and instructions with 32-bit absolute operands
2168 if ( fKind == Reference::pointer ) {
2169 if ( fTarget->isImportProxy() )
2170 return true;
2171 else
2172 return slideable;
2173 }
2174 return false;
2175 #else
2176 #error
2177 #endif
2178 }
2179
2180 bool Reference::isLazyReference() const
2181 {
2182 return fLazy;
2183 }
2184
2185 ObjectFile::Reference::Kind Reference::getKind() const
2186 {
2187 return fKind;
2188 }
2189
2190 uint64_t Reference::getFixUpOffset() const
2191 {
2192 return fFixUpOffsetInSrc;
2193 }
2194
2195 const char* Reference::getTargetName() const
2196 {
2197 if ( fTargetName != NULL )
2198 return fTargetName;
2199 return fTarget->getName();
2200 }
2201
2202 ObjectFile::Atom& Reference::getTarget() const
2203 {
2204 return *fTarget;
2205 }
2206
2207 void Reference::setTarget(ObjectFile::Atom& target, uint64_t offset)
2208 {
2209 fTarget = &target;
2210 fTargetOffset = offset;
2211 }
2212
2213
2214 ObjectFile::Atom& Reference::getFromTarget() const
2215 {
2216 return *fFromTarget;
2217 }
2218
2219 bool Reference::hasFromTarget() const
2220 {
2221 return ( (fFromTarget != NULL) || (fFromTargetName != NULL) );
2222 }
2223
2224 const char* Reference::getFromTargetName() const
2225 {
2226 if ( fFromTargetName != NULL )
2227 return fFromTargetName;
2228 return fFromTarget->getName();
2229 }
2230
2231 void Reference::setFromTarget(ObjectFile::Atom& target)
2232 {
2233 fFromTarget = &target;
2234 }
2235
2236 void Reference::setFromTargetName(const char* name)
2237 {
2238 fFromTargetName = name;
2239 }
2240
2241 void Reference::setFromTargetOffset(uint64_t offset)
2242 {
2243 fFromTargetOffset = offset;
2244 }
2245
2246 uint64_t Reference::getTargetOffset() const
2247 {
2248 return fTargetOffset;
2249 }
2250
2251
2252 uint64_t Reference::getFromTargetOffset() const
2253 {
2254 return fFromTargetOffset;
2255 }
2256
2257 void Reference::setLazy(bool lazy)
2258 {
2259 fLazy = lazy;
2260 }
2261
2262 void Reference::setWeak(bool weak)
2263 {
2264 fWeak = weak;
2265 }
2266
2267 const char* Reference::getDescription() const
2268 {
2269 static char temp[256];
2270 if ( fKind == pointer32Difference ) {
2271 // by-name references have quoted names
2272 bool targetByName = ( &(this->getTarget()) == NULL );
2273 bool fromByName = ( &(this->getFromTarget()) == NULL );
2274 const char* targetQuotes = targetByName ? "\"" : "";
2275 const char* fromQuotes = fromByName ? "\"" : "";
2276 sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %lld) - (&%s%s%s + %lld)",
2277 this->getFixUpOffset(), targetQuotes, this->getTargetName(), targetQuotes, this->getTargetOffset(),
2278 fromQuotes, this->getFromTargetName(), fromQuotes, this->getFromTargetOffset() );
2279 }
2280 else if ( fKind == pointer64Difference ) {
2281 // by-name references have quoted names
2282 bool targetByName = ( &(this->getTarget()) == NULL );
2283 bool fromByName = ( &(this->getFromTarget()) == NULL );
2284 const char* targetQuotes = targetByName ? "\"" : "";
2285 const char* fromQuotes = fromByName ? "\"" : "";
2286 sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %lld) - (&%s%s%s + %lld)",
2287 this->getFixUpOffset(), targetQuotes, this->getTargetName(), targetQuotes, this->getTargetOffset(),
2288 fromQuotes, this->getFromTargetName(), fromQuotes, this->getFromTargetOffset() );
2289 }
2290 else {
2291 switch( fKind ) {
2292 case noFixUp:
2293 sprintf(temp, "reference to ");
2294 break;
2295 case pointer:
2296 {
2297 const char* weak = "";
2298 if ( fWeak )
2299 weak = "weak ";
2300 const char* lazy = "";
2301 if ( fLazy )
2302 lazy = "lazy ";
2303 sprintf(temp, "offset 0x%04llX, %s%spointer to ", this->getFixUpOffset(), weak, lazy);
2304 }
2305 break;
2306 case ppcFixupBranch14:
2307 case ppcFixupBranch24:
2308 sprintf(temp, "offset 0x%04llX, bl pc-rel fixup to ", this->getFixUpOffset());
2309 break;
2310 case ppcFixupPicBaseLow16:
2311 sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
2312 break;
2313 case ppcFixupPicBaseLow14:
2314 sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
2315 break;
2316 case ppcFixupPicBaseHigh16:
2317 sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
2318 break;
2319 case ppcFixupAbsLow16:
2320 sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", this->getFixUpOffset());
2321 break;
2322 case ppcFixupAbsLow14:
2323 sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", this->getFixUpOffset());
2324 break;
2325 case ppcFixupAbsHigh16:
2326 sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", this->getFixUpOffset());
2327 break;
2328 case ppcFixupAbsHigh16AddLow:
2329 sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", this->getFixUpOffset());
2330 break;
2331 case pointer32Difference:
2332 case pointer64Difference:
2333 // handled above
2334 break;
2335 case x86FixupBranch32:
2336 sprintf(temp, "offset 0x%04llX, pc-rel fixup to ", this->getFixUpOffset());
2337 break;
2338 }
2339 // always quote by-name references
2340 if ( fTargetName != NULL ) {
2341 strcat(temp, "\"");
2342 strcat(temp, fTargetName);
2343 strcat(temp, "\"");
2344 }
2345 else if ( fTarget != NULL ) {
2346 strcat(temp, fTarget->getDisplayName());
2347 }
2348 else {
2349 strcat(temp, "NULL target");
2350 }
2351 if ( fTargetOffset != 0 )
2352 sprintf(&temp[strlen(temp)], " plus 0x%08llX", this->getTargetOffset());
2353 if ( (fKind==pointer) && fLazy ) {
2354 strcat(temp, " initially bound to \"");
2355 if ( (fFromTarget != NULL) || (fFromTargetName != NULL) ) {
2356 strcat(temp, this->getFromTargetName());
2357 strcat(temp, "\"");
2358 if ( this->getFromTargetOffset() != 0 )
2359 sprintf(&temp[strlen(temp)], " plus 0x%08llX", this->getFromTargetOffset());
2360 }
2361 else {
2362 strcat(temp, "\" << missing >>");
2363 }
2364 }
2365 }
2366 return temp;
2367 }
2368
2369 };
2370
2371
2372
2373
2374
2375
2376