]> git.saurik.com Git - apple/ld64.git/blame - src/Readers/ObjectFileMachO.cpp
ld64-26.0.81.tar.gz
[apple/ld64.git] / src / Readers / ObjectFileMachO.cpp
CommitLineData
6e880c60
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
c2646906
A
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 */
c2646906
A
24
25
26namespace ObjectFileMachO {
27
28class Reference : public ObjectFile::Reference
29{
30public:
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
6e880c60
A
37 virtual bool isTargetUnbound() const;
38 virtual bool isFromTargetUnbound() const;
c2646906 39 virtual bool isWeakReference() const;
6e880c60 40 virtual bool requiresRuntimeFixUp(bool slideable) const;
c2646906
A
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;
6e880c60 47 virtual bool hasFromTarget() const;
c2646906
A
48 virtual ObjectFile::Atom& getFromTarget() const;
49 virtual const char* getFromTargetName() const;
6e880c60 50 virtual void setTarget(ObjectFile::Atom&, uint64_t offset);
c2646906
A
51 virtual void setFromTarget(ObjectFile::Atom&);
52 virtual void setFromTargetName(const char*);
6e880c60 53 virtual void setFromTargetOffset(uint64_t);
c2646906
A
54 virtual const char* getDescription() const;
55 virtual uint64_t getFromTargetOffset() const;
56
57 void setLazy(bool);
58 void setWeak(bool);
59private:
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
74class Reader : public ObjectFile::Reader
75{
76public:
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
87private:
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
119class Segment : public ObjectFile::Segment
120{
121public:
122 virtual const char* getName() const;
123 virtual bool isContentReadable() const;
124 virtual bool isContentWritable() const;
125 virtual bool isContentExecutable() const;
126protected:
127 Segment(const macho_section*);
128 friend class Reader;
129private:
130 const macho_section* fSection;
131};
132
133class Atom : public ObjectFile::Atom
134{
135public:
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
165protected:
166 friend class Reader;
167 Atom(Reader&, const macho_nlist*);
168 Atom(Reader&, uint32_t offset);
169 virtual ~Atom();
170
6e880c60 171 const macho_section* findSectionFromOffset(uint32_t offset);
c2646906
A
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
197Reader* MakeReader(const macho_header* mh, const char* path, const ObjectFile::ReaderOptions& options)
198{
199 return new Reader(mh, path, options);
200}
201
202
203Reader::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
209Reader::Reader(const char* path)
210 : fPath(NULL), fOptions(*(new ObjectFile::ReaderOptions())), fHeader(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL),
6e880c60 211 fIndirectTable(NULL), fNonAtomStabsStartIndex(0), fNonAtomStabsCount(0)
c2646906
A
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
227Reader::~Reader()
228{
229}
230
231
232bool Atom::atomCompare(const Atom* lhs, const Atom* rhs)
233{
234 return lhs->fOffset < rhs->fOffset;
235}
236
237
238
239void 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;
6e880c60 346 //printf("cleave offset 0x%08X, don't cleave=%d, isSymbol=%d\n", cleavePoint, dontCleavePoints.count(cleavePoint), symbolAtomOffsets.count(cleavePoint));
c2646906
A
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 }
6e880c60 400
c2646906
A
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
527void 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);
6e880c60
A
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 {
c2646906
A
725 srcAtom->addByNameReference(offsetInSrcAtom, Reference::pointer, targetName, addend, 0);
726 }
6e880c60
A
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 }
c2646906 744 else {
c2646906
A
745 srcAtom->addReference(offsetInSrcAtom, Reference::pointer, *dstAtom, addend, 0);
746 }
747 }
6e880c60
A
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 }
c2646906 763 else {
c2646906
A
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);
6e880c60
A
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);
c2646906
A
797 }
798 else {
6e880c60
A
799 dstAddr = targetSymbol->n_value();
800 dst = findAtomCoveringOffset(dstAddr);
801 macho_uintptr_t addend = pointerValue - dstAddr;
802 src->addReference(offsetInSrcAtom, kind, *dst, addend, 0);
c2646906 803 }
6e880c60
A
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);
c2646906
A
814 }
815 else {
6e880c60 816 fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", src->getDisplayName(), refs.size());
c2646906
A
817 }
818 }
6e880c60
A
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
c2646906 822 src->addReference(offsetInSrcAtom, kind, *dst, 0, 0);
c2646906
A
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
1044void 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
1051Atom* 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 }
6e880c60
A
1072 // possible that last atom is zero length
1073 Atom* lastAtom = fAtoms.back();
1074 if ( (lastAtom->fOffset == offset) && (lastAtom->fSize == 0) )
1075 return lastAtom;
c2646906
A
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
6e880c60 1084 throwf("address 0x%08X is not in any atom", offset);
c2646906
A
1085}
1086
1087uint32_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
1099static 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
1105void 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
1113void 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
1122const 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
1134void 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
6e880c60 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());
c2646906
A
1241 if ( !reloc->r_extern() ) {
1242 macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
6e880c60
A
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
c2646906 1248 if ( reloc->r_pcrel() )
6e880c60 1249 pointerValue += reloc->r_address() + sect->addr() + sizeof(macho_uintptr_t);
c2646906
A
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
1326Segment* 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
1340macho_uintptr_t Reader::commonsOffset()
1341{
1342 return fSegment->vmsize();
1343}
1344
1345const char* Reader::getPath()
1346{
1347 return fPath;
1348}
1349
1350std::vector<class ObjectFile::Atom*>& Reader::getAtoms()
1351{
1352 return (std::vector<class ObjectFile::Atom*>&)(fAtoms);
1353}
1354
1355std::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
1362std::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
1401void 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
1422void 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
1452Atom::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);
c2646906
A
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
1500Atom::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);
c2646906
A
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
1552Atom::~Atom()
1553{
1554}
1555
1556macho_section Atom::fgCommonsSection;
1557
1558
1559bool Atom::isLazyStub()
1560{
1561 return ( (fSection->flags() & SECTION_TYPE) == S_SYMBOL_STUBS);
1562}
1563
1564const 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
1573ObjectFile::Reader* Atom::getFile() const
1574{
1575 return &fOwner;
1576}
1577
1578
1579const char* Atom::getName() const
1580{
1581 if ( fSymbol != NULL )
1582 return &fOwner.fStrings[fSymbol->n_strx()];
1583 else
1584 return fSynthesizedName;
1585}
1586
1587const 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
1600ObjectFile::Atom::Scope Atom::getScope() const
1601{
1602 return fScope;
1603}
1604
1605void Atom::setScope(ObjectFile::Atom::Scope newScope)
1606{
1607 fScope = newScope;
1608}
1609
1610
1611bool 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
1627bool Atom::isTentativeDefinition() const
1628{
1629 return (fSection == &fgCommonsSection);
1630}
1631
1632bool 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
1645bool 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
1657bool Atom::isZeroFill() const
1658{
1659 return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL);
1660}
1661
1662bool Atom::dontDeadStrip() const
1663{
1664 if ( fSymbol != NULL )
1665 return ( (fSymbol->n_desc() & N_NO_DEAD_STRIP) != 0 );
1666 return false;
1667}
1668
1669
1670bool Atom::dontStripName() const
1671{
1672 if ( fSymbol != NULL )
1673 return ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0 );
1674 return false;
1675}
1676
1677bool Atom::isImportProxy() const
1678{
1679 return false;
1680}
1681
1682
1683uint64_t Atom::getSize() const
1684{
1685 //return fOffset;
1686 return fSize;
1687}
1688
1689
1690std::vector<ObjectFile::Reference*>& Atom::getReferences() const
1691{
1692 return (std::vector<ObjectFile::Reference*>&)(fReferences);
1693}
1694
1695bool Atom::mustRemainInSection() const
1696{
1697 return true;
1698}
1699
1700const 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
1711Segment& Atom::getSegment() const
1712{
1713 return *fSegment;
1714}
1715
1716bool 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
1726ObjectFile::Atom& Atom::getFollowOnAtom() const
1727{
1728 uint32_t myIndex = fOwner.findAtomIndex(*this);
1729 return *fOwner.fAtoms[myIndex+1];
1730}
1731
1732std::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
1773uint8_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
1798void 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
1809void 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());
6e880c60
A
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());
c2646906
A
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)) ) {
6e880c60
A
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());
c2646906
A
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
6e880c60 2014const macho_section* Atom::findSectionFromOffset(uint32_t offset)
c2646906
A
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 }
6e880c60 2022 throwf("address 0x%08X is not in any section", offset);
c2646906
A
2023}
2024
2025void Atom::setSize(macho_uintptr_t size)
2026{
2027 fSize = size;
2028}
2029
2030
2031void Atom::setFollowOnAtom(Atom&)
2032{
2033
2034}
2035
2036Reference* 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
2045Reference* 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
2062Reference* 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
2070Reference* 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
2079Segment::Segment(const macho_section* sect)
2080 : fSection(sect)
2081{
2082}
2083
2084const char* Segment::getName() const
2085{
2086 return fSection->segname();
2087}
2088
2089bool Segment::isContentReadable() const
2090{
2091 return true;
2092}
2093
2094bool 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
2103bool Segment::isContentExecutable() const
2104{
2105 return ( strcmp(fSection->segname(), "__TEXT") == 0 );
2106}
2107
2108
2109Reference::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
2115Reference::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
2121Reference::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
2141Reference::~Reference()
2142{
2143}
2144
6e880c60 2145bool Reference::isTargetUnbound() const
c2646906 2146{
6e880c60
A
2147 return ( fTarget == NULL );
2148}
2149
2150bool Reference::isFromTargetUnbound() const
2151{
2152 return ( fFromTarget == NULL );
c2646906
A
2153}
2154
2155bool Reference::isWeakReference() const
2156{
2157 return fWeak;
2158}
2159
6e880c60 2160bool Reference::requiresRuntimeFixUp(bool slideable) const
c2646906 2161{
6e880c60
A
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
c2646906
A
2178}
2179
2180bool Reference::isLazyReference() const
2181{
2182 return fLazy;
2183}
2184
2185ObjectFile::Reference::Kind Reference::getKind() const
2186{
2187 return fKind;
2188}
2189
2190uint64_t Reference::getFixUpOffset() const
2191{
2192 return fFixUpOffsetInSrc;
2193}
2194
2195const char* Reference::getTargetName() const
2196{
2197 if ( fTargetName != NULL )
2198 return fTargetName;
2199 return fTarget->getName();
2200}
2201
2202ObjectFile::Atom& Reference::getTarget() const
2203{
2204 return *fTarget;
2205}
2206
6e880c60 2207void Reference::setTarget(ObjectFile::Atom& target, uint64_t offset)
c2646906
A
2208{
2209 fTarget = &target;
6e880c60 2210 fTargetOffset = offset;
c2646906
A
2211}
2212
2213
2214ObjectFile::Atom& Reference::getFromTarget() const
2215{
2216 return *fFromTarget;
2217}
2218
6e880c60
A
2219bool Reference::hasFromTarget() const
2220{
2221 return ( (fFromTarget != NULL) || (fFromTargetName != NULL) );
2222}
2223
c2646906
A
2224const char* Reference::getFromTargetName() const
2225{
2226 if ( fFromTargetName != NULL )
2227 return fFromTargetName;
2228 return fFromTarget->getName();
2229}
2230
2231void Reference::setFromTarget(ObjectFile::Atom& target)
2232{
2233 fFromTarget = &target;
2234}
2235
2236void Reference::setFromTargetName(const char* name)
2237{
2238 fFromTargetName = name;
2239}
2240
6e880c60
A
2241void Reference::setFromTargetOffset(uint64_t offset)
2242{
2243 fFromTargetOffset = offset;
2244}
2245
c2646906
A
2246uint64_t Reference::getTargetOffset() const
2247{
2248 return fTargetOffset;
2249}
2250
2251
2252uint64_t Reference::getFromTargetOffset() const
2253{
2254 return fFromTargetOffset;
2255}
2256
2257void Reference::setLazy(bool lazy)
2258{
2259 fLazy = lazy;
2260}
2261
2262void Reference::setWeak(bool weak)
2263{
2264 fWeak = weak;
2265}
2266
2267const 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:
6e880c60 2336 sprintf(temp, "offset 0x%04llX, pc-rel fixup to ", this->getFixUpOffset());
c2646906
A
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 \"");
6e880c60
A
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 }
c2646906
A
2364 }
2365 }
2366 return temp;
2367}
2368
2369};
2370
2371
2372
2373
2374
2375
2376