]> git.saurik.com Git - apple/ld64.git/blob - src/MachOReaderRelocatable.hpp
466d5df0c4b5f3088365bcbc0f8a1211d591d9ef
[apple/ld64.git] / src / MachOReaderRelocatable.hpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005-2008 Apple 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 #ifndef __OBJECT_FILE_MACH_O__
26 #define __OBJECT_FILE_MACH_O__
27
28 #include <stdint.h>
29 #include <math.h>
30 #include <unistd.h>
31 #include <sys/param.h>
32
33 #include <vector>
34 #include <set>
35 #include <algorithm>
36
37 #include "MachOFileAbstraction.hpp"
38 #include "Architectures.hpp"
39 #include "ObjectFile.h"
40 #include "dwarf2.h"
41 #include "debugline.h"
42
43
44 //
45 //
46 // To implement architecture xxx, you must write template specializations for the following six methods:
47 // Reader<xxx>::validFile()
48 // Reader<xxx>::validSectionType()
49 // Reader<xxx>::addRelocReference()
50 // Reference<xxx>::getDescription()
51 //
52 //
53
54
55
56 extern __attribute__((noreturn)) void throwf(const char* format, ...);
57 extern void warning(const char* format, ...);
58
59 namespace mach_o {
60 namespace relocatable {
61
62
63
64 class ReferenceSorter
65 {
66 public:
67 bool operator()(const ObjectFile::Reference* left, const ObjectFile::Reference* right)
68 {
69 return ( left->getFixUpOffset() < right->getFixUpOffset() );
70 }
71 };
72
73
74 // forward reference
75 template <typename A> class Reader;
76
77 struct AtomAndOffset
78 {
79 AtomAndOffset(ObjectFile::Atom* a=NULL) : atom(a), offset(0) {}
80 AtomAndOffset(ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
81 ObjectFile::Atom* atom;
82 uint32_t offset;
83 };
84
85
86 template <typename A>
87 class Reference : public ObjectFile::Reference
88 {
89 public:
90 typedef typename A::P P;
91 typedef typename A::P::uint_t pint_t;
92 typedef typename A::ReferenceKinds Kinds;
93
94 Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget);
95 Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget);
96 Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset);
97
98 virtual ~Reference() {}
99
100
101 virtual ObjectFile::Reference::TargetBinding getTargetBinding() const;
102 virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const;
103 virtual uint8_t getKind() const { return (uint8_t)fKind; }
104 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
105 virtual const char* getTargetName() const { return (fToTargetName != NULL) ? fToTargetName : fToTarget.atom->getName(); }
106 virtual ObjectFile::Atom& getTarget() const { return *fToTarget.atom; }
107 virtual uint64_t getTargetOffset() const { return (int64_t)((int32_t)fToTarget.offset); }
108 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget.atom; }
109 virtual const char* getFromTargetName() const { return (fFromTargetName != NULL) ? fFromTargetName : fFromTarget.atom->getName(); }
110 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fToTarget.atom = &target; fToTarget.offset = offset; }
111 virtual void setToTargetOffset(uint64_t offset) { fToTarget.offset = offset; }
112 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget.atom = &target; }
113 virtual void setFromTargetName(const char* name) { fFromTargetName = name; }
114 virtual void setFromTargetOffset(uint64_t offset) { fFromTarget.offset = offset; }
115 virtual const char* getDescription() const;
116 virtual uint64_t getFromTargetOffset() const { return fFromTarget.offset; }
117
118 static bool fgForFinalLinkedImage;
119
120 private:
121 pint_t fFixUpOffsetInSrc;
122 AtomAndOffset fToTarget;
123 AtomAndOffset fFromTarget;
124 const char* fToTargetName;
125 const char* fFromTargetName;
126 Kinds fKind;
127
128 };
129
130 template <typename A> bool Reference<A>::fgForFinalLinkedImage = true;
131
132 template <typename A>
133 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget)
134 : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fToTargetName(NULL), fFromTargetName(NULL),
135 fKind(kind)
136 {
137 // make reference a by-name unless:
138 // - the reference type is only used with direct references
139 // - the target is translation unit scoped
140 // - the target kind is not regular (is weak or tentative)
141 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate)
142 && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
143 && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition) ) {
144 fToTargetName = toTarget.atom->getName();
145 //fprintf(stderr, "Reference(): changing to by-name %p %s, target scope=%d, target section=%s\n", toTarget.atom, fToTargetName, toTarget.atom->getScope(), toTarget.atom->getSectionName());
146 fToTarget.atom = NULL;
147 }
148 ((class BaseAtom*)at.atom)->addReference(this);
149 //fprintf(stderr, "Reference(): %p fToTarget<%s, %08X>\n", this, (fToTarget.atom != NULL) ? fToTarget.atom->getDisplayName() : fToTargetName , fToTarget.offset);
150 }
151
152 template <typename A>
153 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget)
154 : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fFromTarget(fromTarget),
155 fToTargetName(NULL), fFromTargetName(NULL), fKind(kind)
156 {
157 // make reference a by-name where needed
158 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate)
159 && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
160 && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
161 && (toTarget.atom != at.atom) ) {
162 fToTargetName = toTarget.atom->getName();
163 fToTarget.atom = NULL;
164 }
165 ((class BaseAtom*)at.atom)->addReference(this);
166 //fprintf(stderr, "Reference(): %p kind=%d, fToTarget<%s, %08X>, fromTarget<%s, %08X>\n", this, kind,
167 // this->getTargetName(), fToTarget.offset, this->getFromTargetName(), fromTarget.offset);
168 }
169
170 template <typename A>
171 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset)
172 : fFixUpOffsetInSrc(at.offset),
173 fToTargetName(toName), fFromTargetName(NULL), fKind(kind)
174 {
175 fToTarget.offset = toOffset;
176 ((class BaseAtom*)at.atom)->addReference(this);
177 }
178
179 template <typename A>
180 ObjectFile::Reference::TargetBinding Reference<A>::getTargetBinding() const
181 {
182 if ( fgForFinalLinkedImage ) {
183 if ( (fKind == A::kDtraceProbe) || (fKind == A::kDtraceProbeSite) || (fKind == A::kDtraceIsEnabledSite) || (fKind == A::kDtraceTypeReference) )
184 return ObjectFile::Reference::kDontBind;
185 }
186 if ( fToTarget.atom == NULL )
187 return ObjectFile::Reference::kUnboundByName;
188 if ( fToTargetName == NULL )
189 return ObjectFile::Reference::kBoundDirectly;
190 else
191 return ObjectFile::Reference::kBoundByName;
192 }
193
194 template <typename A>
195 ObjectFile::Reference::TargetBinding Reference<A>::getFromTargetBinding() const
196 {
197 if ( fFromTarget.atom == NULL ) {
198 if ( fFromTargetName == NULL )
199 return ObjectFile::Reference::kDontBind;
200 else
201 return ObjectFile::Reference::kUnboundByName;
202 }
203 else {
204 if ( fFromTargetName == NULL )
205 return ObjectFile::Reference::kBoundDirectly;
206 else
207 return ObjectFile::Reference::kBoundByName;
208 }
209 }
210
211
212
213 template <typename A>
214 class Segment : public ObjectFile::Segment
215 {
216 public:
217 Segment(const macho_section<typename A::P>* sect);
218 virtual const char* getName() const { return fSection->segname(); }
219 virtual bool isContentReadable() const { return true; }
220 virtual bool isContentWritable() const { return fWritable; }
221 virtual bool isContentExecutable() const { return fExecutable; }
222 private:
223 const macho_section<typename A::P>* fSection;
224 bool fWritable;
225 bool fExecutable;
226 };
227
228 template <typename A>
229 Segment<A>::Segment(const macho_section<typename A::P>* sect)
230 : fSection(sect), fWritable(true), fExecutable(false)
231 {
232 if ( strcmp(fSection->segname(), "__TEXT") == 0 ) {
233 fWritable = false;
234 fExecutable = true;
235 }
236 else if ( strcmp(fSection->segname(), "__IMPORT") == 0 ) {
237 fWritable = true;
238 fExecutable = true;
239 }
240 }
241
242
243 class DataSegment : public ObjectFile::Segment
244 {
245 public:
246 virtual const char* getName() const { return "__DATA"; }
247 virtual bool isContentReadable() const { return true; }
248 virtual bool isContentWritable() const { return true; }
249 virtual bool isContentExecutable() const { return false; }
250
251 static DataSegment fgSingleton;
252 };
253
254 DataSegment DataSegment::fgSingleton;
255
256 class LinkEditSegment : public ObjectFile::Segment
257 {
258 public:
259 virtual const char* getName() const { return "__LINKEDIT"; }
260 virtual bool isContentReadable() const { return true; }
261 virtual bool isContentWritable() const { return false; }
262 virtual bool isContentExecutable() const { return false; }
263
264 static LinkEditSegment fgSingleton;
265 };
266
267 LinkEditSegment LinkEditSegment::fgSingleton;
268
269 class BaseAtom : public ObjectFile::Atom
270 {
271 public:
272 BaseAtom() : fStabsStartIndex(0), fStabsCount(0) {}
273
274 virtual void setSize(uint64_t size) = 0;
275 virtual void addReference(ObjectFile::Reference* ref) = 0;
276 virtual void sortReferences() = 0;
277 virtual void addLineInfo(const ObjectFile::LineInfo& info) = 0;
278 virtual uint64_t getObjectAddress() const = 0;
279 virtual uint32_t getOrdinal() const { return fOrdinal; }
280 virtual void setOrdinal(uint32_t value) { fOrdinal = value; }
281 virtual const void* getSectionRecord() const = 0;
282 virtual bool isAlias() const { return false; }
283
284 uint32_t fStabsStartIndex;
285 uint32_t fStabsCount;
286 uint32_t fOrdinal;
287 };
288
289 class BaseAtomSorter
290 {
291 public:
292 bool operator()(const class BaseAtom* left, const class BaseAtom* right) {
293 if ( left == right )
294 return false;
295 uint64_t leftAddr = left->getObjectAddress();
296 uint64_t rightAddr = right->getObjectAddress();
297 if ( leftAddr < rightAddr ) {
298 return true;
299 }
300 else if ( leftAddr > rightAddr ) {
301 return false;
302 }
303 else {
304 // if they have same address, one might be the end of a section and the other the start of the next section
305 const void* leftSection = left->getSectionRecord();
306 const void* rightSection = right->getSectionRecord();
307 if ( leftSection != rightSection ) {
308 return ( leftSection < rightSection );
309 }
310 // if they have same address and section, one might be an alias
311 bool leftAlias = left->isAlias();
312 bool rightAlias = right->isAlias();
313 if ( leftAlias && rightAlias ) {
314 // sort multiple aliases for same address first by scope
315 ObjectFile::Atom::Scope leftScope = left->getScope();
316 ObjectFile::Atom::Scope rightScope = right->getScope();
317 if ( leftScope != rightScope ) {
318 return ( leftScope < rightScope );
319 }
320 // sort multiple aliases for same address then by name
321 return ( strcmp(left->getName(), right->getName()) < 0 );
322 }
323 else if ( leftAlias ) {
324 return true;
325 }
326 else if ( rightAlias ) {
327 return false;
328 }
329 else {
330 // they must be tentative defintions
331 switch ( left->getDefinitionKind() ) {
332 case ObjectFile::Atom::kTentativeDefinition:
333 // sort tentative definitions by name
334 return ( strcmp(left->getName(), right->getName()) < 0 );
335 case ObjectFile::Atom::kAbsoluteSymbol:
336 // sort absolute symbols with same address by name
337 return ( strcmp(left->getName(), right->getName()) < 0 );
338 default:
339 // hack for rdar://problem/5102873
340 if ( !left->isZeroFill() || !right->isZeroFill() )
341 warning("atom sorting error for %s and %s in %s", left->getDisplayName(), right->getDisplayName(), left->getFile()->getPath());
342 break;
343 }
344 }
345 }
346 return false;
347 }
348 };
349
350
351 //
352 // A SymbolAtom represents a chunk of a mach-o object file that has a symbol table entry
353 // pointing to it. A C function or global variable is represented by one of these atoms.
354 //
355 //
356 template <typename A>
357 class SymbolAtom : public BaseAtom
358 {
359 public:
360 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
361 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
362 { return fOwner.getTranslationUnitSource(dir, name); }
363 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
364 virtual const char* getDisplayName() const { return getName(); }
365 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
366 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ((fSymbol->n_desc() & N_WEAK_DEF) != 0)
367 ? ObjectFile::Atom::kWeakDefinition : ObjectFile::Atom::kRegularDefinition; }
368 virtual SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
369 virtual bool dontDeadStrip() const;
370 virtual bool isZeroFill() const { return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL); }
371 virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
372 virtual uint64_t getSize() const { return fSize; }
373 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
374 virtual bool mustRemainInSection() const { return true; }
375 virtual const char* getSectionName() const;
376 virtual Segment<A>& getSegment() const { return *fSegment; }
377 virtual ObjectFile::Atom& getFollowOnAtom() const;
378 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return (std::vector<ObjectFile::LineInfo>*)&fLineInfo; }
379 virtual ObjectFile::Alignment getAlignment() const { return fAlignment; }
380 virtual void copyRawContent(uint8_t buffer[]) const;
381 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
382 virtual void setSize(uint64_t size);
383 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
384 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
385 virtual void addLineInfo(const ObjectFile::LineInfo& info) { fLineInfo.push_back(info); }
386 virtual uint64_t getObjectAddress() const { return fAddress; }
387 virtual const void* getSectionRecord() const { return (const void*)fSection; }
388
389 protected:
390 typedef typename A::P P;
391 typedef typename A::P::E E;
392 typedef typename A::P::uint_t pint_t;
393 typedef typename A::ReferenceKinds Kinds;
394 typedef typename std::vector<Reference<A>*> ReferenceVector;
395 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
396 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
397 friend class Reader<A>;
398
399 SymbolAtom(Reader<A>&, const macho_nlist<P>*, const macho_section<P>*);
400 virtual ~SymbolAtom() {}
401
402 Reader<A>& fOwner;
403 const macho_nlist<P>* fSymbol;
404 pint_t fAddress;
405 pint_t fSize;
406 const macho_section<P>* fSection;
407 Segment<A>* fSegment;
408 ReferenceVector fReferences;
409 std::vector<ObjectFile::LineInfo> fLineInfo;
410 ObjectFile::Atom::Scope fScope;
411 SymbolTableInclusion fSymbolTableInclusion;
412 ObjectFile::Alignment fAlignment;
413 };
414
415
416 template <typename A>
417 SymbolAtom<A>::SymbolAtom(Reader<A>& owner, const macho_nlist<P>* symbol, const macho_section<P>* section)
418 : fOwner(owner), fSymbol(symbol), fAddress(0), fSize(0), fSection(section), fSegment(NULL), fAlignment(0)
419 {
420 uint8_t type = symbol->n_type();
421 if ( (type & N_EXT) == 0 )
422 fScope = ObjectFile::Atom::scopeTranslationUnit;
423 else if ( (type & N_PEXT) != 0 )
424 fScope = ObjectFile::Atom::scopeLinkageUnit;
425 else
426 fScope = ObjectFile::Atom::scopeGlobal;
427 if ( (type & N_TYPE) == N_SECT ) {
428 // real definition
429 fSegment = new Segment<A>(fSection);
430 fAddress = fSymbol->n_value();
431 pint_t sectionStartAddr = section->addr();
432 pint_t sectionEndAddr = section->addr()+section->size();
433 if ( (fAddress < sectionStartAddr) || (fAddress > (sectionEndAddr)) ) {
434 throwf("malformed .o file, symbol %s with address 0x%0llX is not with section %d (%s,%s) address range of 0x%0llX to 0x%0llX",
435 this->getName(), (uint64_t)fAddress, fSymbol->n_sect(), section->segname(), section->sectname(),
436 (uint64_t)sectionStartAddr, (uint64_t)(sectionEndAddr) );
437 }
438 }
439 else {
440 warning("unknown symbol type: %d", type);
441 }
442
443 //fprintf(stderr, "SymbolAtom(%p) %s fAddress=0x%X\n", this, this->getDisplayName(), (uint32_t)fAddress);
444 // support for .o files built with old ld64
445 if ( (fSymbol->n_desc() & N_WEAK_DEF) && (strcmp(fSection->sectname(),"__picsymbolstub1__TEXT") == 0) ) {
446 const char* name = this->getName();
447 const int nameLen = strlen(name);
448 if ( (nameLen > 6) && strcmp(&name[nameLen-5], "$stub") == 0 ) {
449 // switch symbol to point at name that does not have trailing $stub
450 char correctName[nameLen];
451 strncpy(correctName, name, nameLen-5);
452 correctName[nameLen-5] = '\0';
453 const macho_nlist<P>* symbolsStart = fOwner.fSymbols;
454 const macho_nlist<P>* symbolsEnd = &symbolsStart[fOwner.fSymbolCount];
455 for(const macho_nlist<P>* s = symbolsStart; s < symbolsEnd; ++s) {
456 if ( strcmp(&fOwner.fStrings[s->n_strx()], correctName) == 0 ) {
457 fSymbol = s;
458 break;
459 }
460 }
461 }
462 }
463 // support for labeled stubs
464 switch ( section->flags() & SECTION_TYPE ) {
465 case S_SYMBOL_STUBS:
466 setSize(section->reserved2());
467 break;
468 case S_LAZY_SYMBOL_POINTERS:
469 case S_NON_LAZY_SYMBOL_POINTERS:
470 setSize(sizeof(pint_t));
471 break;
472 case S_4BYTE_LITERALS:
473 setSize(4);
474 break;
475 case S_8BYTE_LITERALS:
476 setSize(8);
477 break;
478 case S_16BYTE_LITERALS:
479 setSize(16);
480 break;
481 case S_CSTRING_LITERALS:
482 setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1);
483 break;
484 case S_REGULAR:
485 case S_ZEROFILL:
486 case S_COALESCED:
487 // size calculate later after next atom is found
488 break;
489 }
490
491 // compute whether this atom needs to be in symbol table
492 if ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0) {
493 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAndNeverStrip;
494 }
495 else if ( fOwner.fOptions.fForFinalLinkedImage
496 && ((section->flags() & SECTION_TYPE) == S_COALESCED)
497 && ((section->flags() & S_ATTR_NO_TOC) == S_ATTR_NO_TOC)
498 && ((section->flags() & S_ATTR_STRIP_STATIC_SYMS) == S_ATTR_STRIP_STATIC_SYMS)
499 && (strcmp(section->sectname(), "__eh_frame") == 0) ) {
500 // .eh symbols exist so the linker can associate them with functions
501 // removing them from final linked images is a big space savings rdar://problem/4180168
502 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
503 }
504 else if ( fOwner.fOptions.fForFinalLinkedImage
505 && ((section->flags() & SECTION_TYPE) == S_REGULAR)
506 && (strncmp(section->sectname(), "__gcc_except_tab", 16) == 0)
507 && (strncmp(this->getName(), "GCC_except_table", 16) == 0) ) {
508 // GCC_except_table* symbols don't need to exist in final linked image
509 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
510 }
511 else if ( fOwner.fOptions.fForFinalLinkedImage && !fOwner.fOptions.fForStatic && (fOwner.fStrings[fSymbol->n_strx()] == 'l') ) {
512 // labels beginning with a lowercase ell are automatically removed in final linked images <rdar://problem/4571042>
513 // xnu code base uses a lot of asesembly labels that start with 'l', don't strip those (static executable)
514 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
515 }
516 else {
517 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
518 }
519 // compute alignment
520 fAlignment = ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
521
522 // work around malformed icc generated .o files <rdar://problem/5349847>
523 // if section starts with a symbol and that symbol address does not match section alignment, then force it to
524 if ( (section->addr() == fAddress) && (fAlignment.modulus != 0) )
525 fAlignment.modulus = 0;
526 }
527
528 template <typename A>
529 bool SymbolAtom<A>::dontDeadStrip() const
530 {
531 // the symbol can have a no-dead-strip bit
532 if ( (fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0 )
533 return true;
534 // or the section can have a no-dead-strip bit
535 return ( fSection->flags() & S_ATTR_NO_DEAD_STRIP );
536 }
537
538
539 template <typename A>
540 const char* SymbolAtom<A>::getSectionName() const
541 {
542 if ( fOwner.fOptions.fForFinalLinkedImage && (strcmp(fSection->sectname(), "__textcoal_nt") == 0) )
543 return "__text";
544
545 if ( strlen(fSection->sectname()) > 15 ) {
546 static char temp[18];
547 strncpy(temp, fSection->sectname(), 16);
548 temp[17] = '\0';
549 return temp;
550 }
551 return fSection->sectname();
552 }
553
554 template <typename A>
555 ObjectFile::Atom& SymbolAtom<A>::getFollowOnAtom() const
556 {
557 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
558 Reference<A>* ref = *it;
559 if ( ref->getKind() == A::kFollowOn )
560 return ref->getTarget();
561 }
562 return *((ObjectFile::Atom*)NULL);
563 }
564
565
566 class Beyond
567 {
568 public:
569 Beyond(uint64_t offset) : fOffset(offset) {}
570 bool operator()(ObjectFile::Reference* ref) const {
571 return ( ref->getFixUpOffset() >= fOffset );
572 }
573 private:
574 uint64_t fOffset;
575 };
576
577
578 template <typename A>
579 void SymbolAtom<A>::setSize(uint64_t size)
580 {
581 // when resizing, any references beyond the new size are tossed
582 if ( (fSize != 0) && (fReferences.size() > 0) )
583 fReferences.erase(std::remove_if(fReferences.begin(), fReferences.end(), Beyond(size)), fReferences.end());
584 // set new size
585 fSize = size;
586 }
587
588 template <typename A>
589 void SymbolAtom<A>::copyRawContent(uint8_t buffer[]) const
590 {
591 // copy base bytes
592 if ( isZeroFill() )
593 bzero(buffer, fSize);
594 else {
595 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
596 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
597 }
598 }
599
600 //
601 // A SymbolAliasAtom represents an alternate name for a SymbolAtom
602 //
603 //
604 template <typename A>
605 class SymbolAliasAtom : public BaseAtom
606 {
607 public:
608 virtual ObjectFile::Reader* getFile() const { return fAliasOf.getFile(); }
609 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
610 { return fAliasOf.getTranslationUnitSource(dir, name); }
611 virtual const char* getName() const { return fName; }
612 virtual const char* getDisplayName() const { return fName; }
613 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
614 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fAliasOf.getDefinitionKind(); }
615 virtual SymbolTableInclusion getSymbolTableInclusion() const { return fAliasOf.getSymbolTableInclusion(); }
616 virtual bool dontDeadStrip() const { return fDontDeadStrip; }
617 virtual bool isZeroFill() const { return fAliasOf.isZeroFill(); }
618 virtual bool isThumb() const { return fAliasOf.isThumb(); }
619 virtual uint64_t getSize() const { return 0; }
620 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
621 virtual bool mustRemainInSection() const { return true; }
622 virtual const char* getSectionName() const { return fAliasOf.getSectionName(); }
623 virtual Segment<A>& getSegment() const { return (Segment<A>&)fAliasOf.getSegment(); }
624 virtual ObjectFile::Atom& getFollowOnAtom() const { return (ObjectFile::Atom&)fAliasOf; }
625 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
626 virtual ObjectFile::Alignment getAlignment() const { return fAliasOf.getAlignment(); }
627 virtual void copyRawContent(uint8_t buffer[]) const {}
628 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
629 virtual void setSize(uint64_t size) { }
630 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
631 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
632 virtual void addLineInfo(const ObjectFile::LineInfo& info) { }
633 virtual uint64_t getObjectAddress() const { return fAliasOf.getObjectAddress(); }
634 virtual const void* getSectionRecord() const { return fAliasOf.getSectionRecord(); }
635 virtual bool isAlias() const { return true; }
636
637 protected:
638 typedef typename A::P P;
639 typedef typename std::vector<Reference<A>*> ReferenceVector;
640 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
641 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
642 friend class Reader<A>;
643
644 SymbolAliasAtom(const char* name, const macho_nlist<P>*, const BaseAtom& );
645 virtual ~SymbolAliasAtom() {}
646
647 const char* fName;
648 const BaseAtom& fAliasOf;
649 ObjectFile::Atom::Scope fScope;
650 bool fDontDeadStrip;
651 ReferenceVector fReferences;
652 };
653
654
655 template <typename A>
656 SymbolAliasAtom<A>::SymbolAliasAtom(const char* name, const macho_nlist<P>* symbol, const BaseAtom& aliasOf)
657 : fName(name), fAliasOf(aliasOf)
658 {
659 //fprintf(stderr, "SymbolAliasAtom(%p) %s\n", this, name);
660 if ( symbol != NULL ) {
661 uint8_t type = symbol->n_type();
662 if ( (type & N_EXT) == 0 )
663 fScope = ObjectFile::Atom::scopeTranslationUnit;
664 else if ( (type & N_PEXT) != 0 )
665 fScope = ObjectFile::Atom::scopeLinkageUnit;
666 else
667 fScope = ObjectFile::Atom::scopeGlobal;
668 fDontDeadStrip = ((symbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0);
669 }
670 else {
671 // aliases defined on the command line are initially global scope
672 fScope = ObjectFile::Atom::scopeGlobal;
673 fDontDeadStrip = false;
674 }
675 // add follow-on reference to real atom
676 new Reference<A>(A::kFollowOn, AtomAndOffset(this), AtomAndOffset((ObjectFile::Atom*)&aliasOf));
677 }
678
679
680 //
681 // A TentativeAtom represents a C "common" or "tentative" defintion of data.
682 // For instance, "int foo;" is neither a declaration or a definition and
683 // is represented by a TentativeAtom.
684 //
685 template <typename A>
686 class TentativeAtom : public BaseAtom
687 {
688 public:
689 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
690 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
691 { return fOwner.getTranslationUnitSource(dir, name); }
692 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
693 virtual const char* getDisplayName() const { return getName(); }
694 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
695 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kTentativeDefinition; }
696 virtual bool isZeroFill() const { return true; }
697 virtual bool isThumb() const { return false; }
698 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
699 ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
700 virtual bool dontDeadStrip() const { return ((fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); }
701 virtual uint64_t getSize() const { return fSymbol->n_value(); }
702 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
703 virtual bool mustRemainInSection() const { return true; }
704 virtual const char* getSectionName() const;
705 virtual ObjectFile::Segment& getSegment() const { return DataSegment::fgSingleton; }
706 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
707 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
708 virtual ObjectFile::Alignment getAlignment() const;
709 virtual void copyRawContent(uint8_t buffer[]) const;
710 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
711 virtual void setSize(uint64_t size) { }
712 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
713 virtual void sortReferences() { }
714 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
715 virtual uint64_t getObjectAddress() const { return ULLONG_MAX; }
716 virtual const void* getSectionRecord() const { return NULL; }
717
718 protected:
719 typedef typename A::P P;
720 typedef typename A::P::E E;
721 typedef typename A::P::uint_t pint_t;
722 typedef typename A::ReferenceKinds Kinds;
723 friend class Reader<A>;
724
725 TentativeAtom(Reader<A>&, const macho_nlist<P>*);
726 virtual ~TentativeAtom() {}
727
728 Reader<A>& fOwner;
729 const macho_nlist<P>* fSymbol;
730 ObjectFile::Atom::Scope fScope;
731 static std::vector<ObjectFile::Reference*> fgNoReferences;
732 };
733
734 template <typename A>
735 std::vector<ObjectFile::Reference*> TentativeAtom<A>::fgNoReferences;
736
737 template <typename A>
738 TentativeAtom<A>::TentativeAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
739 : fOwner(owner), fSymbol(symbol)
740 {
741 uint8_t type = symbol->n_type();
742 if ( (type & N_EXT) == 0 )
743 fScope = ObjectFile::Atom::scopeTranslationUnit;
744 else if ( (type & N_PEXT) != 0 )
745 fScope = ObjectFile::Atom::scopeLinkageUnit;
746 else
747 fScope = ObjectFile::Atom::scopeGlobal;
748 if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) {
749 // tentative definition
750 }
751 else {
752 warning("unknown symbol type: %d", type);
753 }
754 //fprintf(stderr, "TentativeAtom(%p) %s\n", this, this->getDisplayName());
755 }
756
757
758 template <typename A>
759 ObjectFile::Alignment TentativeAtom<A>::getAlignment() const
760 {
761 uint8_t alignment = GET_COMM_ALIGN(fSymbol->n_desc());
762 if ( alignment == 0 ) {
763 // common symbols align to their size
764 // that is, a 4-byte common aligns to 4-bytes
765 // if this size is not a power of two,
766 // then round up to the next power of two
767 uint64_t size = this->getSize();
768 alignment = 63 - (uint8_t)__builtin_clzll(size);
769 if ( size != (1ULL << alignment) )
770 ++alignment;
771 }
772 // limit alignment of extremely large commons to 2^15 bytes (8-page)
773 if ( alignment < 12 )
774 return ObjectFile::Alignment(alignment);
775 else
776 return ObjectFile::Alignment(12);
777 }
778
779 template <typename A>
780 const char* TentativeAtom<A>::getSectionName() const
781 {
782 if ( fOwner.fOptions.fForFinalLinkedImage || fOwner.fOptions.fMakeTentativeDefinitionsReal )
783 return "__common";
784 else
785 return "._tentdef";
786 }
787
788
789 template <typename A>
790 void TentativeAtom<A>::copyRawContent(uint8_t buffer[]) const
791 {
792 bzero(buffer, getSize());
793 }
794
795
796 //
797 // An AnonymousAtom represents compiler generated data that has no name.
798 // For instance, a literal C-string or a 64-bit floating point constant
799 // is represented by an AnonymousAtom.
800 //
801 template <typename A>
802 class AnonymousAtom : public BaseAtom
803 {
804 public:
805 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
806 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
807 virtual const char* getName() const { return fSynthesizedName; }
808 virtual const char* getDisplayName() const;
809 virtual ObjectFile::Atom::Scope getScope() const;
810 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fKind; }
811 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
812 virtual bool dontDeadStrip() const { return fDontDeadStrip; }
813 virtual bool isZeroFill() const;
814 virtual bool isThumb() const { return false; }
815 virtual uint64_t getSize() const { return fSize; }
816 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
817 virtual bool mustRemainInSection() const { return true; }
818 virtual const char* getSectionName() const;
819 virtual Segment<A>& getSegment() const { return *fSegment; }
820 virtual ObjectFile::Atom& getFollowOnAtom() const;
821 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
822 virtual ObjectFile::Alignment getAlignment() const;
823 virtual void copyRawContent(uint8_t buffer[]) const;
824 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
825 virtual void setSize(uint64_t size) { fSize = size; }
826 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
827 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
828 virtual void addLineInfo(const ObjectFile::LineInfo& info) { warning("can't add line info to anonymous symbol %s from %s", this->getDisplayName(), this->getFile()->getPath()); }
829 virtual uint64_t getObjectAddress() const { return fAddress; }
830 virtual const void* getSectionRecord() const { return (const void*)fSection; }
831 BaseAtom* redirectTo() { return fRedirect; }
832 bool isWeakImportStub() { return fWeakImportStub; }
833 void resolveName();
834
835 protected:
836 typedef typename A::P P;
837 typedef typename A::P::E E;
838 typedef typename A::P::uint_t pint_t;
839 typedef typename A::ReferenceKinds Kinds;
840 typedef typename std::vector<Reference<A>*> ReferenceVector;
841 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
842 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
843 friend class Reader<A>;
844
845 AnonymousAtom(Reader<A>&, const macho_section<P>*, pint_t addr, pint_t size);
846 virtual ~AnonymousAtom() {}
847 static bool cstringsHaveLabels();
848
849 Reader<A>& fOwner;
850 const char* fSynthesizedName;
851 const char* fDisplayName;
852 const macho_section<P>* fSection;
853 pint_t fAddress;
854 pint_t fSize;
855 Segment<A>* fSegment;
856 ReferenceVector fReferences;
857 BaseAtom* fRedirect;
858 bool fDontDeadStrip;
859 bool fWeakImportStub;
860 ObjectFile::Atom::SymbolTableInclusion fSymbolTableInclusion;
861 ObjectFile::Atom::Scope fScope;
862 ObjectFile::Atom::DefinitionKind fKind;
863 };
864
865 template <typename A>
866 AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* section, pint_t addr, pint_t size)
867 : fOwner(owner), fSynthesizedName(NULL), fDisplayName(NULL), fSection(section), fAddress(addr), fSize(size),
868 fSegment(NULL), fDontDeadStrip(true), fWeakImportStub(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn),
869 fScope(ObjectFile::Atom::scopeTranslationUnit), fKind(ObjectFile::Atom::kRegularDefinition)
870 {
871 fSegment = new Segment<A>(fSection);
872 fRedirect = this;
873 uint8_t type = fSection->flags() & SECTION_TYPE;
874 //fprintf(stderr, "AnonymousAtom(%p) addr=0x%llX in %s from %s\n", this, (long long)addr, section->sectname(), owner.getPath());
875 switch ( type ) {
876 case S_ZEROFILL:
877 {
878 asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr);
879 }
880 break;
881 case S_COALESCED:
882 case S_REGULAR:
883 if ( (strcmp(section->sectname(), "__class") == 0) && (strcmp(section->segname(), "__OBJC") == 0) && owner.fAppleObjc ) {
884 // special case ObjC classes to synthesize .objc_class_name_* symbols, for Apple runtime only
885 fSynthesizedName = ".objc_class_name_PENDING";
886 owner.fAtomsPendingAName.push_back(this);
887 owner.fSectionsWithAtomsPendingAName.insert(fSection);
888 if ( fOwner.fOptions.fForFinalLinkedImage )
889 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
890 else
891 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAsAbsolute;
892 fScope = ObjectFile::Atom::scopeGlobal;
893 }
894 else if ( strcmp(fSection->sectname(), "__cstring") == 0 ) {
895 // handle .o files created by old ld64 -r that are missing cstring section type
896 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
897 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
898 }
899 else if ((strcmp(section->sectname(), "__cfstring") == 0) && (strcmp(section->segname(), "__DATA") == 0)) {
900 fSynthesizedName = "cfstring-pointer-name-PENDING";
901 fScope = ObjectFile::Atom::scopeLinkageUnit;
902 owner.fAtomsPendingAName.push_back(this);
903 owner.fSectionsWithAtomsPendingAName.insert(fSection);
904 fDontDeadStrip = false;
905 fKind = ObjectFile::Atom::kWeakDefinition;
906 }
907 break;
908 case S_CSTRING_LITERALS:
909 {
910 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
911 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
912 fScope = ObjectFile::Atom::scopeLinkageUnit;
913 fKind = ObjectFile::Atom::kWeakDefinition;
914 fDontDeadStrip = false;
915 if ( !fOwner.fOptions.fForFinalLinkedImage && cstringsHaveLabels() )
916 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
917 }
918 break;
919 case S_4BYTE_LITERALS:
920 {
921 uint32_t value = E::get32(*(uint32_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
922 asprintf((char**)&fSynthesizedName, "4-byte-literal=0x%08X", value);
923 fScope = ObjectFile::Atom::scopeLinkageUnit;
924 fKind = ObjectFile::Atom::kWeakDefinition;
925 fDontDeadStrip = false;
926 }
927 break;
928 case S_8BYTE_LITERALS:
929 {
930 uint64_t value = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
931 asprintf((char**)&fSynthesizedName, "8-byte-literal=0x%016llX", value);
932 fScope = ObjectFile::Atom::scopeLinkageUnit;
933 fKind = ObjectFile::Atom::kWeakDefinition;
934 fDontDeadStrip = false;
935 }
936 break;
937 case S_16BYTE_LITERALS:
938 {
939 uint64_t value1 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
940 uint64_t value2 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr + 8 - section->addr()));
941 asprintf((char**)&fSynthesizedName, "16-byte-literal=0x%016llX,%016llX", value1, value2);
942 fScope = ObjectFile::Atom::scopeLinkageUnit;
943 fKind = ObjectFile::Atom::kWeakDefinition;
944 fDontDeadStrip = false;
945 }
946 break;
947 case S_LITERAL_POINTERS:
948 {
949 //uint32_t literalNameAddr = P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
950 //const char* str = (char*)(owner.fHeader) + section->offset() + literalNameAddr - section->addr();
951 //asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", section->segname(), section->sectname(), str);
952 fSynthesizedName = "literal-pointer-name-PENDING";
953 fScope = ObjectFile::Atom::scopeLinkageUnit;
954 fKind = ObjectFile::Atom::kWeakDefinition;
955 fDontDeadStrip = false;
956 owner.fAtomsPendingAName.push_back(this);
957 owner.fSectionsWithAtomsPendingAName.insert(fSection);
958 }
959 break;
960 case S_MOD_INIT_FUNC_POINTERS:
961 asprintf((char**)&fSynthesizedName, "initializer$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
962 break;
963 case S_MOD_TERM_FUNC_POINTERS:
964 asprintf((char**)&fSynthesizedName, "terminator$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
965 break;
966 case S_SYMBOL_STUBS:
967 {
968 uint32_t index = (fAddress - fSection->addr()) / fSection->reserved2();
969 index += fSection->reserved1();
970 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
971 const macho_nlist<P>* sym = &fOwner.fSymbols[symbolIndex];
972 uint32_t strOffset = sym->n_strx();
973 // want name to not have $stub suffix, this is what automatic stub generation expects
974 fSynthesizedName = &fOwner.fStrings[strOffset];
975 // check for weak import
976 fWeakImportStub = fOwner.isWeakImportSymbol(sym);
977 // sometimes the compiler gets confused and generates a stub to a static function
978 // if so, we should redirect any call to the stub to be calls to the real static function atom
979 if ( ((sym->n_type() & N_TYPE) != N_UNDF) && ((sym->n_type() & N_EXT) == 0) ) {
980 BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName);
981 if ( staticAtom != NULL )
982 fRedirect = staticAtom;
983 }
984 fKind = ObjectFile::Atom::kWeakDefinition;
985 // might be a spurious stub for a static function, make stub static too
986 if ( (sym->n_type() & N_EXT) == 0 )
987 fScope = ObjectFile::Atom::scopeTranslationUnit;
988 else
989 fScope = ObjectFile::Atom::scopeLinkageUnit;
990 }
991 break;
992 case S_LAZY_SYMBOL_POINTERS:
993 case S_NON_LAZY_SYMBOL_POINTERS:
994 {
995 fDontDeadStrip = false;
996 fScope = ObjectFile::Atom::scopeLinkageUnit;
997 uint32_t index = (fAddress - fSection->addr()) / sizeof(pint_t);
998 index += fSection->reserved1();
999 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
1000 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
1001 // Silly codegen with non-lazy pointer to a local symbol
1002 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1003 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset)));
1004 // All atoms not created yet, so we need to scan symbol table
1005 const macho_nlist<P>* closestSym = NULL;
1006 const macho_nlist<P>* end = &fOwner.fSymbols[fOwner.fSymbolCount];
1007 for (const macho_nlist<P>* sym = fOwner.fSymbols; sym < end; ++sym) {
1008 if ( ((sym->n_type() & N_TYPE) == N_SECT)
1009 && ((sym->n_type() & N_STAB) == 0) ) {
1010 if ( sym->n_value() == nonLazyPtrValue ) {
1011 const char* name = &fOwner.fStrings[sym->n_strx()];
1012 char* str = new char[strlen(name)+16];
1013 strcpy(str, name);
1014 strcat(str, "$non_lazy_ptr");
1015 fSynthesizedName = str;
1016 // add direct reference to target later, because its atom may not be constructed yet
1017 fOwner.fLocalNonLazys.push_back(this);
1018 fScope = ObjectFile::Atom::scopeTranslationUnit;
1019 return;
1020 }
1021 else if ( (sym->n_value() < nonLazyPtrValue) && ((closestSym == NULL) || (sym->n_value() > closestSym->n_value())) ) {
1022 closestSym = sym;
1023 }
1024 }
1025 }
1026 // add direct reference to target later, because its atom may not be constructed yet
1027 if ( closestSym != NULL ) {
1028 const char* name = &fOwner.fStrings[closestSym->n_strx()];
1029 char* str;
1030 asprintf(&str, "%s+%u$non_lazy_ptr", name, nonLazyPtrValue - closestSym->n_value());
1031 fSynthesizedName = str;
1032 }
1033 else {
1034 fSynthesizedName = "$interior$non_lazy_ptr";
1035 }
1036 fScope = ObjectFile::Atom::scopeTranslationUnit;
1037 fOwner.fLocalNonLazys.push_back(this);
1038 return;
1039 }
1040 const macho_nlist<P>* targetSymbol = &fOwner.fSymbols[symbolIndex];
1041 const char* name = &fOwner.fStrings[targetSymbol->n_strx()];
1042 char* str = new char[strlen(name)+16];
1043 strcpy(str, name);
1044 if ( type == S_LAZY_SYMBOL_POINTERS )
1045 strcat(str, "$lazy_ptr");
1046 else
1047 strcat(str, "$non_lazy_ptr");
1048 fSynthesizedName = str;
1049
1050 // optimize __IMPORT segment out of i386 dyld or if -slow_stubs is used
1051 if ( (fOwner.fOptions.fForDyld || fOwner.fOptions.fSlowx86Stubs) && (strcmp(fSection->segname(),"__IMPORT") == 0) ) {
1052 macho_section<P>* dummySection = new macho_section<P>(*fSection);
1053 dummySection->set_segname("__DATA");
1054 dummySection->set_sectname("__nl_symbol_ptr");
1055 fSection = dummySection;
1056 fSegment = new Segment<A>(fSection);
1057 }
1058
1059 if ( type == S_NON_LAZY_SYMBOL_POINTERS )
1060 fKind = ObjectFile::Atom::kWeakDefinition;
1061
1062 if ( (targetSymbol->n_type() & N_EXT) == 0 ) {
1063 // target is translation unit scoped, so add direct reference to target
1064 //fOwner.makeReference(A::kPointer, addr, targetSymbol->n_value());
1065 new Reference<A>(A::kPointer, AtomAndOffset(this), fOwner.findAtomAndOffset(targetSymbol->n_value()));
1066 }
1067 else {
1068 if ( fOwner.isWeakImportSymbol(targetSymbol) )
1069 new Reference<A>(A::kPointerWeakImport, AtomAndOffset(this), name, 0);
1070 else
1071 new Reference<A>(A::kPointer, AtomAndOffset(this), name, 0);
1072 }
1073 }
1074 break;
1075 default:
1076 throwf("section type %d not supported with address=0x%08X", type, addr);
1077 }
1078 //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName());
1079 }
1080
1081 // x86_64 uses L labels on cstrings to allow relocs with addends
1082 template <> bool AnonymousAtom<x86_64>::cstringsHaveLabels() { return true; }
1083 template <typename A> bool AnonymousAtom<A>::cstringsHaveLabels() { return false; }
1084
1085
1086 template <typename A>
1087 void AnonymousAtom<A>::resolveName()
1088 {
1089 if ( (strcmp(fSection->sectname(), "__class") == 0) && (strcmp(fSection->segname(), "__OBJC") == 0) ) {
1090 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1091 // references are not yet sorted, so scan the vector
1092 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1093 if ( ((*rit)->getFixUpOffset() == sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1094 const char* superStr = (*rit)->getTargetName();
1095 if ( strncmp(superStr, "cstring=", 8) == 0 ) {
1096 const char* superClassName;
1097 asprintf((char**)&superClassName, ".objc_class_name_%s", &superStr[8]);
1098 new Reference<A>(A::kNoFixUp, AtomAndOffset(this), superClassName, 0);
1099 }
1100 break;
1101 }
1102 }
1103 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1104 if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1105 const char* classStr = (*rit)->getTargetName();
1106 if ( strncmp(classStr, "cstring=", 8) == 0 ) {
1107 asprintf((char**)&fSynthesizedName, ".objc_class_name_%s", &classStr[8]);
1108 }
1109 break;
1110 }
1111 }
1112 }
1113 else if ( (fSection->flags() & SECTION_TYPE) == S_LITERAL_POINTERS) {
1114 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1115 if ( references.size() < 1 )
1116 throwf("S_LITERAL_POINTERS section %s,%s missing relocs", fSection->segname(), fSection->sectname());
1117 ObjectFile::Reference* ref = references[0];
1118 const char* str = ref->getTargetName();
1119 if ( strncmp(str, "cstring=", 8) == 0 ) {
1120 asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", fSection->segname(), fSection->sectname(), &str[8]);
1121 }
1122 }
1123 else if ( (strcmp(fSection->sectname(), "__cfstring") == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
1124 // references are not yet sorted, so scan the vector
1125 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1126 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1127 if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1128 const char* superStr = (*rit)->getTargetName();
1129 if ( (superStr != NULL) && (strncmp(superStr, "cstring=", 8) == 0) ) {
1130 asprintf((char**)&fSynthesizedName, "cfstring=%s", &superStr[8]);
1131 }
1132 else {
1133 // compiled with -fwritable-strings or a non-ASCII string
1134 ObjectFile::Atom& stringDataAtom = (*rit)->getTarget();
1135 uint8_t buffer[stringDataAtom.getSize()];
1136 stringDataAtom.copyRawContent(buffer);
1137 fKind = ObjectFile::Atom::kRegularDefinition; // these are not coalescable
1138 fScope = ObjectFile::Atom::scopeTranslationUnit;
1139 fSynthesizedName = "cfstring-not-coalesable";
1140 }
1141 break;
1142 }
1143 }
1144 }
1145 }
1146
1147
1148 template <typename A>
1149 const char* AnonymousAtom<A>::getDisplayName() const
1150 {
1151 if ( fSynthesizedName != NULL )
1152 return fSynthesizedName;
1153
1154 if ( fDisplayName != NULL )
1155 return fDisplayName;
1156
1157 if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) {
1158 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1159 asprintf((char**)&fDisplayName, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset);
1160 }
1161 else {
1162 asprintf((char**)&fDisplayName, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() );
1163 }
1164 return fDisplayName;
1165 }
1166
1167
1168 template <typename A>
1169 ObjectFile::Atom::Scope AnonymousAtom<A>::getScope() const
1170 {
1171 return fScope;
1172 }
1173
1174
1175 template <typename A>
1176 bool AnonymousAtom<A>::isZeroFill() const
1177 {
1178 return ( (fSection->flags() & SECTION_TYPE) == S_ZEROFILL );
1179 }
1180
1181
1182 template <typename A>
1183 const char* AnonymousAtom<A>::getSectionName() const
1184 {
1185 if ( strlen(fSection->sectname()) > 15 ) {
1186 static char temp[18];
1187 strncpy(temp, fSection->sectname(), 16);
1188 temp[17] = '\0';
1189 return temp;
1190 }
1191 return fSection->sectname();
1192 }
1193
1194 template <typename A>
1195 ObjectFile::Alignment AnonymousAtom<A>::getAlignment() const
1196 {
1197 switch ( fSection->flags() & SECTION_TYPE ) {
1198 case S_4BYTE_LITERALS:
1199 return ObjectFile::Alignment(2);
1200 case S_8BYTE_LITERALS:
1201 return ObjectFile::Alignment(3);
1202 case S_16BYTE_LITERALS:
1203 return ObjectFile::Alignment(4);
1204 case S_NON_LAZY_SYMBOL_POINTERS:
1205 return ObjectFile::Alignment((uint8_t)log2(sizeof(pint_t)));
1206 case S_CSTRING_LITERALS:
1207 if ( ! fOwner.fOptions.fForFinalLinkedImage )
1208 return ObjectFile::Alignment(fSection->align());
1209 default:
1210 return ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
1211 }
1212 }
1213
1214
1215 template <typename A>
1216 ObjectFile::Atom& AnonymousAtom<A>::getFollowOnAtom() const
1217 {
1218 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
1219 Reference<A>* ref = *it;
1220 if ( ref->getKind() == A::kFollowOn )
1221 return ref->getTarget();
1222 }
1223 return *((ObjectFile::Atom*)NULL);
1224 }
1225
1226 template <typename A>
1227 void AnonymousAtom<A>::copyRawContent(uint8_t buffer[]) const
1228 {
1229 // copy base bytes
1230 if ( isZeroFill() )
1231 bzero(buffer, fSize);
1232 else {
1233 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1234 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
1235 }
1236 }
1237
1238
1239 //
1240 // An AbsoluteAtom represents an N_ABS symbol which can only be created in
1241 // assembly language and usable by static executables such as the kernel/
1242 //
1243 template <typename A>
1244 class AbsoluteAtom : public BaseAtom
1245 {
1246 public:
1247 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
1248 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
1249 { return fOwner.getTranslationUnitSource(dir, name); }
1250 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
1251 virtual const char* getDisplayName() const { return getName(); }
1252 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
1253 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kAbsoluteSymbol; }
1254 virtual bool isZeroFill() const { return false; }
1255 virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
1256 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableInAsAbsolute; }
1257 virtual bool dontDeadStrip() const { return false; }
1258 virtual uint64_t getSize() const { return 0; }
1259 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
1260 virtual bool mustRemainInSection() const { return true; }
1261 virtual const char* getSectionName() const { return "._absolute"; }
1262 virtual ObjectFile::Segment& getSegment() const { return LinkEditSegment::fgSingleton; }
1263 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
1264 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
1265 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1266 virtual void copyRawContent(uint8_t buffer[]) const { }
1267 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
1268 virtual void setSize(uint64_t size) { }
1269 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
1270 virtual void sortReferences() { }
1271 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
1272 virtual uint64_t getObjectAddress() const { return fSymbol->n_value(); }
1273 virtual void setSectionOffset(uint64_t offset) { /* don't let fSectionOffset be altered*/ }
1274 virtual const void* getSectionRecord() const { return NULL; }
1275
1276 protected:
1277 typedef typename A::P P;
1278 typedef typename A::P::E E;
1279 typedef typename A::P::uint_t pint_t;
1280 typedef typename A::ReferenceKinds Kinds;
1281 friend class Reader<A>;
1282
1283 AbsoluteAtom(Reader<A>&, const macho_nlist<P>*);
1284 virtual ~AbsoluteAtom() {}
1285
1286 Reader<A>& fOwner;
1287 const macho_nlist<P>* fSymbol;
1288 ObjectFile::Atom::Scope fScope;
1289 static std::vector<ObjectFile::Reference*> fgNoReferences;
1290 };
1291
1292 template <typename A>
1293 std::vector<ObjectFile::Reference*> AbsoluteAtom<A>::fgNoReferences;
1294
1295 template <typename A>
1296 AbsoluteAtom<A>::AbsoluteAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
1297 : fOwner(owner), fSymbol(symbol)
1298 {
1299 // store absolute adress in fSectionOffset
1300 fSectionOffset = symbol->n_value();
1301 // compute scope
1302 uint8_t type = symbol->n_type();
1303 if ( (type & N_EXT) == 0 )
1304 fScope = ObjectFile::Atom::scopeTranslationUnit;
1305 else if ( (type & N_PEXT) != 0 )
1306 fScope = ObjectFile::Atom::scopeLinkageUnit;
1307 else
1308 fScope = ObjectFile::Atom::scopeGlobal;
1309 //fprintf(stderr, "AbsoluteAtom(%p) %s\n", this, this->getDisplayName());
1310 }
1311
1312
1313
1314 template <typename A>
1315 class Reader : public ObjectFile::Reader
1316 {
1317 public:
1318 static bool validFile(const uint8_t* fileContent);
1319 Reader(const uint8_t* fileContent, const char* path, time_t modTime,
1320 const ObjectFile::ReaderOptions& options, uint32_t ordinalBase);
1321 virtual ~Reader() {}
1322
1323 virtual const char* getPath() { return fPath; }
1324 virtual time_t getModificationTime() { return fModTime; }
1325 virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return fDebugInfo; }
1326 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return (std::vector<class ObjectFile::Atom*>&)(fAtoms); }
1327 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
1328 virtual std::vector<Stab>* getStabs() { return &fStabs; }
1329 virtual ObjectFile::Reader::ObjcConstraint getObjCConstraint() { return fObjConstraint; }
1330 virtual uint32_t updateCpuConstraint(uint32_t current);
1331 virtual bool canScatterAtoms() { return (fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS); }
1332 virtual bool objcReplacementClasses(){ return fReplacementClasses; }
1333 virtual bool hasLongBranchStubs() { return fHasLongBranchStubs; }
1334
1335 bool getTranslationUnitSource(const char** dir, const char** name) const;
1336
1337 private:
1338 typedef typename A::P P;
1339 typedef typename A::P::E E;
1340 typedef typename A::P::uint_t pint_t;
1341 //typedef typename std::vector<Atom<A>*> AtomVector;
1342 //typedef typename AtomVector::iterator AtomVectorIterator; // seems to help C++ parser
1343 typedef typename A::ReferenceKinds Kinds;
1344 friend class AnonymousAtom<A>;
1345 friend class TentativeAtom<A>;
1346 friend class AbsoluteAtom<A>;
1347 friend class SymbolAtom<A>;
1348 typedef std::map<pint_t, BaseAtom*> AddrToAtomMap;
1349
1350 void addReferencesForSection(const macho_section<P>* sect);
1351 bool addRelocReference(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
1352 bool addRelocReference_powerpc(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
1353 bool read_comp_unit(const char ** name, const char ** comp_dir, uint64_t *stmt_list);
1354 static bool isWeakImportSymbol(const macho_nlist<P>* sym);
1355 static bool skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, uint8_t addr_size, bool dwarf64);
1356 static const char* assureFullPath(const char* path);
1357 AtomAndOffset findAtomAndOffset(pint_t addr);
1358 AtomAndOffset findAtomAndOffset(pint_t baseAddr, pint_t realAddr);
1359 Reference<A>* makeReference(Kinds kind, pint_t atAddr, pint_t toAddr);
1360 Reference<A>* makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr);
1361 Reference<A>* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr);
1362 Reference<A>* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr);
1363 Reference<A>* makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset);
1364 Reference<A>* makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect);
1365 Reference<A>* makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset);
1366 void validSectionType(uint8_t type);
1367 void addDtraceExtraInfos(uint32_t probeAddr, const char* providerName);
1368 void setCpuConstraint(uint32_t cpusubtype);
1369
1370 BaseAtom* findAtomByName(const char*);
1371
1372 const char* fPath;
1373 time_t fModTime;
1374 uint32_t fOrdinalBase;
1375 const ObjectFile::ReaderOptions& fOptions;
1376 const macho_header<P>* fHeader;
1377 const char* fStrings;
1378 const macho_nlist<P>* fSymbols;
1379 uint32_t fSymbolCount;
1380 const macho_segment_command<P>* fSegment;
1381 const uint32_t* fIndirectTable;
1382 std::vector<BaseAtom*> fAtoms;
1383 AddrToAtomMap fAddrToAtom;
1384 AddrToAtomMap fAddrToAbsoluteAtom;
1385 std::vector<class AnonymousAtom<A>*> fLocalNonLazys;
1386 std::vector<class AnonymousAtom<A>*> fAtomsPendingAName;
1387 std::set<const macho_section<P>*> fSectionsWithAtomsPendingAName;
1388 std::vector<const char*> fDtraceProviderInfo;
1389 ObjectFile::Reader::DebugInfoKind fDebugInfo;
1390 bool fHasUUID;
1391 const macho_section<P>* fDwarfDebugInfoSect;
1392 const macho_section<P>* fDwarfDebugAbbrevSect;
1393 const macho_section<P>* fDwarfDebugLineSect;
1394 const char* fDwarfTranslationUnitDir;
1395 const char* fDwarfTranslationUnitFile;
1396 std::map<uint32_t,const char*> fDwarfIndexToFile;
1397 std::vector<Stab> fStabs;
1398 bool fAppleObjc;
1399 bool fHasDTraceProbes;
1400 bool fHaveIndirectSymbols;
1401 bool fReplacementClasses;
1402 bool fHasLongBranchStubs;
1403 ObjectFile::Reader::ObjcConstraint fObjConstraint;
1404 uint32_t fCpuConstraint;
1405 };
1406
1407 template <typename A>
1408 Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options, uint32_t ordinalBase)
1409 : fPath(strdup(path)), fModTime(modTime), fOrdinalBase(ordinalBase), fOptions(options), fHeader((const macho_header<P>*)fileContent),
1410 fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL),
1411 fDebugInfo(kDebugInfoNone), fHasUUID(false), fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL), fDwarfDebugLineSect(NULL),
1412 fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL), fAppleObjc(false), fHasDTraceProbes(false),
1413 fHaveIndirectSymbols(false), fReplacementClasses(false), fHasLongBranchStubs(false),
1414 fObjConstraint(ObjectFile::Reader::kObjcNone), fCpuConstraint(ObjectFile::Reader::kCpuAny)
1415 {
1416 // sanity check
1417 if ( ! validFile(fileContent) )
1418 throw "not a valid mach-o object file";
1419
1420 Reference<A>::fgForFinalLinkedImage = options.fForFinalLinkedImage;
1421
1422 // write out path for -t or -whatsloaded option
1423 if ( options.fLogObjectFiles || options.fLogAllFiles )
1424 printf("%s\n", path);
1425
1426 // cache intersting pointers
1427 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1428 this->setCpuConstraint(header->cpusubtype());
1429 const uint32_t cmd_count = header->ncmds();
1430 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
1431 const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
1432 const macho_load_command<P>* cmd = cmds;
1433 uint32_t undefinedStartIndex = 0;
1434 uint32_t undefinedEndIndex = 0;
1435 for (uint32_t i = 0; i < cmd_count; ++i) {
1436 switch (cmd->cmd()) {
1437 case LC_SYMTAB:
1438 {
1439 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
1440 fSymbolCount = symtab->nsyms();
1441 fSymbols = (const macho_nlist<P>*)((char*)header + symtab->symoff());
1442 fStrings = (char*)header + symtab->stroff();
1443 if ( undefinedEndIndex == 0 ) {
1444 undefinedStartIndex = 0;
1445 undefinedEndIndex = symtab->nsyms();
1446 }
1447 }
1448 break;
1449 case LC_DYSYMTAB:
1450 {
1451 const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
1452 fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
1453 undefinedStartIndex = dsymtab->iundefsym();
1454 undefinedEndIndex = undefinedStartIndex + dsymtab->nundefsym();
1455 }
1456 break;
1457 case LC_UUID:
1458 fHasUUID = true;
1459 break;
1460
1461 default:
1462 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
1463 fSegment = (macho_segment_command<P>*)cmd;
1464 }
1465 break;
1466 }
1467 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
1468 if ( cmd > cmdsEnd )
1469 throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path);
1470 }
1471
1472 // if there are no load commands, then this file has no content, so no atoms
1473 if ( header->ncmds() < 1 )
1474 return;
1475
1476 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
1477 const macho_section<P>* const sectionsEnd = &sectionsStart[fSegment->nsects()];
1478
1479 // inital guess for number of atoms
1480 fAtoms.reserve(fSymbolCount);
1481
1482 // add all atoms that have entries in symbol table
1483 const macho_section<P>* sections = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
1484 for (int i=fSymbolCount-1; i >= 0 ; --i) {
1485 // walk backwards through symbol table so globals are see before locals, otherwise a local alias would beome the reaal name
1486 const macho_nlist<P>& sym = fSymbols[i];
1487 if ( (sym.n_type() & N_STAB) == 0 ) {
1488 uint8_t type = (sym.n_type() & N_TYPE);
1489 if ( type == N_SECT ) {
1490 const macho_section<P>* section = &sections[sym.n_sect()-1];
1491 pint_t sectionEndAddr = section->addr() + section->size();
1492 bool suppress = false;
1493 // ignore atoms in debugger sections
1494 if ( (section->flags() & S_ATTR_DEBUG) == 0 ) {
1495 if ( strncmp(&fStrings[sym.n_strx()], "__dtrace_probe$", 15) == 0 ) {
1496 // ignore dtrace probe labels
1497 fHasDTraceProbes = true;
1498 }
1499 else if ( fStrings[sym.n_strx()] == 'L' ) {
1500 // ignore L labels, <rdar://problem/3962731>
1501 }
1502 else {
1503 // ignore labels for atoms in other sections
1504 switch ( section->flags() & SECTION_TYPE ) {
1505 case S_REGULAR:
1506 if ( (sym.n_desc() & N_WEAK_DEF) && strcmp(section->sectname(), "__picsymbolstub1__TEXT") == 0 )
1507 suppress = true; // ignore stubs in crt1.o built by old ld64 that was missing S_SYMBOL_STUBS
1508 case S_ZEROFILL:
1509 case S_COALESCED:
1510 case S_4BYTE_LITERALS:
1511 case S_8BYTE_LITERALS:
1512 case S_16BYTE_LITERALS:
1513 case S_CSTRING_LITERALS:
1514 {
1515 BaseAtom* newAtom;
1516 typename AddrToAtomMap::iterator pos = fAddrToAtom.find(sym.n_value());
1517 if ( (pos != fAddrToAtom.end()) && (strcmp(pos->second->getSectionName(), section->sectname())==0) ) {
1518 // another label to an existing address in the same section, make this an alias
1519 newAtom = new SymbolAliasAtom<A>(&fStrings[sym.n_strx()], &sym, *pos->second);
1520 }
1521 else {
1522 // make SymbolAtom atom for this address
1523 newAtom = new SymbolAtom<A>(*this, &sym, section);
1524 // don't add symbols at end of section to addr->atom map
1525 if ( sym.n_value() != sectionEndAddr )
1526 fAddrToAtom[newAtom->getObjectAddress()] = newAtom;
1527 }
1528 if ( ! suppress )
1529 fAtoms.push_back(newAtom);
1530 }
1531 break;
1532 case S_SYMBOL_STUBS:
1533 case S_LAZY_SYMBOL_POINTERS:
1534 case S_NON_LAZY_SYMBOL_POINTERS:
1535 // ignore symboled stubs produces by old ld64
1536 break;
1537 default:
1538 warning("symbol %s found in unsupported section in %s",
1539 &fStrings[sym.n_strx()], this->getPath());
1540 }
1541 }
1542 }
1543 }
1544 else if ( (type == N_UNDF) && (sym.n_value() != 0) ) {
1545 fAtoms.push_back(new TentativeAtom<A>(*this, &sym));
1546 }
1547 else if ( type == N_ABS ) {
1548 const char* symName = &fStrings[sym.n_strx()];
1549 if ( strncmp(symName, ".objc_class_name_", 17) == 0 ) {
1550 // ignore .objc_class_name_* symbols
1551 fAppleObjc = true;
1552 }
1553 else if ( strcmp(&symName[strlen(symName)-3], ".eh") == 0 ) {
1554 // ignore empty *.eh symbols
1555 }
1556 else {
1557 BaseAtom* abAtom = new AbsoluteAtom<A>(*this, &sym);
1558 fAtoms.push_back(abAtom);
1559 fAddrToAbsoluteAtom[sym.n_value()] = abAtom;
1560 }
1561 }
1562 else if ( type == N_INDR ) {
1563 fHaveIndirectSymbols = true;
1564 }
1565 }
1566 }
1567
1568 // add all fixed size anonymous atoms from special sections
1569 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1570 pint_t atomSize = 0;
1571 uint8_t type (sect->flags() & SECTION_TYPE);
1572 validSectionType(type);
1573 bool suppress = false;
1574 switch ( type ) {
1575 case S_SYMBOL_STUBS:
1576 suppress = true;
1577 atomSize = sect->reserved2();
1578 break;
1579 case S_LAZY_SYMBOL_POINTERS:
1580 suppress = true;
1581 atomSize = sizeof(pint_t);
1582 break;
1583 case S_NON_LAZY_SYMBOL_POINTERS:
1584 case S_LITERAL_POINTERS:
1585 case S_MOD_INIT_FUNC_POINTERS:
1586 case S_MOD_TERM_FUNC_POINTERS:
1587 atomSize = sizeof(pint_t);
1588 break;
1589 case S_INTERPOSING:
1590 atomSize = sizeof(pint_t)*2;
1591 break;
1592 case S_4BYTE_LITERALS:
1593 atomSize = 4;
1594 break;
1595 case S_8BYTE_LITERALS:
1596 atomSize = 8;
1597 break;
1598 case S_16BYTE_LITERALS:
1599 atomSize = 16;
1600 break;
1601 case S_REGULAR:
1602 // special case ObjC classes to synthesize .objc_class_name_* symbols
1603 if ( (strcmp(sect->sectname(), "__class") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) && fAppleObjc ) {
1604 // gcc sometimes over aligns class structure
1605 uint32_t align = 1 << sect->align();
1606 atomSize = ((12 * sizeof(pint_t)) + align-1) & (-align);
1607 }
1608 // get objc Garbage Collection info
1609 else if ( ((strcmp(sect->sectname(), "__image_info") == 0) && (strcmp(sect->segname(), "__OBJC") == 0))
1610 || ((strncmp(sect->sectname(), "__objc_imageinfo", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0)) ) {
1611 // struct objc_image_info {
1612 // uint32_t version; // initially 0
1613 // uint32_t flags;
1614 // };
1615 // #define OBJC_IMAGE_SUPPORTS_GC 2
1616 // #define OBJC_IMAGE_GC_ONLY 4
1617 //
1618 const uint32_t* contents = (uint32_t*)(((char*)fHeader) + sect->offset());
1619 if ( (sect->size() >= 8) && (contents[0] == 0) ) {
1620 uint32_t flags = E::get32(contents[1]);
1621 if ( (flags & 4) == 4 )
1622 fObjConstraint = ObjectFile::Reader::kObjcGC;
1623 else if ( (flags & 2) == 2 )
1624 fObjConstraint = ObjectFile::Reader::kObjcRetainReleaseOrGC;
1625 else
1626 fObjConstraint = ObjectFile::Reader::kObjcRetainRelease;
1627 if ( (flags & 1) == 1 )
1628 fReplacementClasses = true;
1629 // don't make atom for this section
1630 atomSize = sect->size();
1631 suppress = true;
1632 }
1633 else {
1634 warning("can't parse __OBJC/__image_info section in %s", fPath);
1635 }
1636 }
1637 // special case constant NS/CFString literals and make an atom out of each one
1638 else if ((strcmp(sect->sectname(), "__cfstring") == 0) && (strcmp(sect->segname(), "__DATA") == 0)) {
1639 atomSize = 4 * sizeof(pint_t);
1640 }
1641 break;
1642 }
1643 if ( atomSize != 0 ) {
1644 for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) {
1645 pint_t atomAddr = sect->addr() + sectOffset;
1646 // add if not already an atom at that address
1647 if ( fAddrToAtom.find(atomAddr) == fAddrToAtom.end() ) {
1648 AnonymousAtom<A>* newAtom = new AnonymousAtom<A>(*this, sect, atomAddr, atomSize);
1649 if ( !suppress )
1650 fAtoms.push_back(newAtom);
1651 fAddrToAtom[atomAddr] = newAtom->redirectTo();
1652 }
1653 }
1654 }
1655 }
1656
1657 // add all c-string anonymous atoms
1658 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1659 if ( ((sect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS) || strcmp(sect->sectname(), "__cstring") == 0 ) {
1660 uint32_t stringLen;
1661 pint_t stringAddr;
1662 BaseAtom* mostAlignedEmptyString = NULL;
1663 uint32_t mostAlignedEmptyStringTrailingZeros = 0;
1664 std::vector<std::pair<pint_t,BaseAtom*> > emptyStrings;
1665 for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += stringLen) {
1666 stringAddr = sect->addr() + sectOffset;
1667 stringLen = strlen((char*)(fHeader) + sect->offset() + sectOffset) + 1;
1668 // add if not already an atom at that address
1669 if ( fAddrToAtom.find(stringAddr) == fAddrToAtom.end() ) {
1670 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, stringAddr, stringLen);
1671 if ( stringLen == 1 ) {
1672 // because of padding it may look like there are lots of empty strings, keep track of all
1673 emptyStrings.push_back(std::make_pair<pint_t,BaseAtom*>(stringAddr, newAtom));
1674 // record empty string with greatest alignment requirement
1675 uint32_t stringAddrTrailingZeros = (stringAddr==0) ? sect->align() : __builtin_ctz(stringAddr);
1676 if ( (mostAlignedEmptyString == NULL)
1677 || ( stringAddrTrailingZeros > mostAlignedEmptyStringTrailingZeros) ) {
1678 mostAlignedEmptyString = newAtom;
1679 mostAlignedEmptyStringTrailingZeros = stringAddrTrailingZeros;
1680 }
1681 }
1682 else {
1683 fAtoms.push_back(newAtom);
1684 fAddrToAtom[stringAddr] = newAtom;
1685 }
1686 }
1687 }
1688 // map all uses of empty strings to the most aligned one
1689 if ( mostAlignedEmptyString != NULL ) {
1690 // make most aligned atom a real atom
1691 fAtoms.push_back(mostAlignedEmptyString);
1692 // map all other empty atoms to this one
1693 for (typename std::vector<std::pair<pint_t,BaseAtom*> >::iterator it=emptyStrings.begin(); it != emptyStrings.end(); it++) {
1694 fAddrToAtom[it->first] = mostAlignedEmptyString;
1695 }
1696 }
1697 }
1698 }
1699
1700 // sort all atoms so far by address and section
1701 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
1702
1703 //fprintf(stderr, "sorted atoms:\n");
1704 //for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++)
1705 // fprintf(stderr, "0x%08llX %s\n", (*it)->getObjectAddress(), (*it)->getDisplayName());
1706
1707 // create atoms to cover any non-debug ranges not handled above
1708 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1709 pint_t sectionStartAddr = sect->addr();
1710 pint_t sectionEndAddr = sect->addr() + sect->size();
1711 const bool setFollowOnAtom = ! this->canScatterAtoms();
1712 if ( sect->size() != 0 ) {
1713 // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change
1714 if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
1715 fDebugInfo = kDebugInfoDwarf;
1716 if ( strcmp(sect->sectname(), "__debug_info") == 0 )
1717 fDwarfDebugInfoSect = sect;
1718 else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 )
1719 fDwarfDebugAbbrevSect = sect;
1720 else if ( strcmp(sect->sectname(), "__debug_line") == 0 )
1721 fDwarfDebugLineSect = sect;
1722 }
1723 else {
1724 if ( strcmp(sect->segname(), "__DWARFA") == 0 ) {
1725 throw "object file contains old DWARF debug info - rebuild with newer compiler";
1726 }
1727 uint8_t type (sect->flags() & SECTION_TYPE);
1728 switch ( type ) {
1729 case S_REGULAR:
1730 case S_ZEROFILL:
1731 case S_COALESCED:
1732 // if there is not an atom already at the start of this section, add an anonymous one
1733 pint_t previousAtomAddr = 0;
1734 BaseAtom* previousAtom = NULL;
1735 if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) {
1736 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr(), 0);
1737 fAddrToAtom[sect->addr()] = newAtom;
1738 fAtoms.push_back(newAtom);
1739 previousAtomAddr = sectionStartAddr;
1740 previousAtom = newAtom;
1741 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
1742 }
1743 // calculate size of all atoms in this section and add follow-on references
1744 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
1745 BaseAtom* atom = (BaseAtom*)(*it);
1746 pint_t atomAddr = atom->getObjectAddress();
1747 if ( atom->getSectionRecord() == sect ) {
1748 //fprintf(stderr, "addr=0x%08llX, atom=%s\n", (uint64_t)atomAddr, atom->getDisplayName());
1749 if ( (previousAtom != NULL) && (previousAtomAddr != atomAddr) ) {
1750 previousAtom->setSize(atomAddr - previousAtomAddr);
1751 if ( setFollowOnAtom && (atom != previousAtom) )
1752 new Reference<A>(A::kFollowOn, AtomAndOffset(previousAtom), AtomAndOffset(atom));
1753 }
1754 previousAtomAddr = atomAddr;
1755 previousAtom = atom;
1756 }
1757 }
1758 if ( previousAtom != NULL ) {
1759 // set last atom in section
1760 previousAtom->setSize(sectionEndAddr - previousAtomAddr);
1761 }
1762 break;
1763 }
1764 }
1765 }
1766 }
1767
1768 // check for object file that defines no objc classes, but uses objc classes
1769 // check for dtrace provider info
1770 for (uint32_t i=undefinedStartIndex; i < undefinedEndIndex; ++i) {
1771 const macho_nlist<P>& sym = fSymbols[i];
1772 if ( (sym.n_type() & N_STAB) == 0 ) {
1773 if ( (sym.n_type() & N_TYPE) == N_UNDF ) {
1774 const char* undefinedName = &fStrings[sym.n_strx()];
1775 if ( !fAppleObjc && (strncmp(undefinedName, ".objc_class_name_", 17) == 0) ) {
1776 fAppleObjc = true;
1777 }
1778 else if ( strncmp(undefinedName, "___dtrace_", 10) == 0 ) {
1779 if ( strchr(undefinedName, '$') != NULL ) {
1780 if ( (strncmp(&undefinedName[10], "probe$", 6) != 0) && (strncmp(&undefinedName[10], "isenabled$", 10) != 0) ) {
1781 // any undefined starting with __dtrace_*$ that is not ___dtrace_probe$* or ___dtrace_isenabled$*
1782 // is extra provider info
1783 fDtraceProviderInfo.push_back(undefinedName);
1784 }
1785 }
1786 }
1787 }
1788 }
1789 }
1790
1791 // add relocation based references to sections that have atoms with pending names
1792 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1793 if ( fSectionsWithAtomsPendingAName.count(sect) != 0 )
1794 addReferencesForSection(sect);
1795 }
1796
1797 // update any anonymous atoms that need references built in order to name themselves
1798 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fAtomsPendingAName.begin(); it != fAtomsPendingAName.end(); it++) {
1799 (*it)->resolveName();
1800 }
1801
1802 // add relocation based references to other sections
1803 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1804 if ( fSectionsWithAtomsPendingAName.count(sect) == 0 )
1805 addReferencesForSection(sect);
1806 }
1807
1808 // add objective-c references
1809 if ( fAppleObjc ) {
1810 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1811 if ( (strcmp(sect->sectname(), "__cls_refs") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) {
1812 for (uint32_t offset = 0; offset < sect->size(); offset += sizeof(pint_t)) {
1813 AtomAndOffset ao = this->findAtomAndOffset(sect->addr()+offset);
1814 ObjectFile::Reference* classRef = ao.atom->getReferences()[0];
1815 if ( classRef->getFixUpOffset() == 0 ) {
1816 const char* classStr = classRef->getTargetName();
1817 if ( strncmp(classStr, "cstring=", 8) == 0 ) {
1818 const char* className;
1819 asprintf((char**)&className, ".objc_class_name_%s", &classStr[8]);
1820 new Reference<A>(A::kNoFixUp, ao, className, 0);
1821 }
1822 }
1823 }
1824 }
1825 }
1826 }
1827
1828 // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed
1829 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fLocalNonLazys.begin(); it != fLocalNonLazys.end(); it++) {
1830 AnonymousAtom<A>* localNonLazy = *it;
1831 uint32_t fileOffset = localNonLazy->fSection->offset() - localNonLazy->fSection->addr() + localNonLazy->fAddress;
1832 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fHeader)+fileOffset)));
1833 makeReference(A::kPointer, localNonLazy->fAddress, nonLazyPtrValue);
1834 }
1835
1836 // add implicit direct reference from each C++ function to its eh info
1837 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1838 if ( ((sect->flags() & SECTION_TYPE) == S_COALESCED) && (strcmp(sect->sectname(), "__eh_frame") == 0) ) {
1839 for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
1840 // note: this algorithm depens on the map iterator returning entries in address order
1841 if ( (it->first >= sect->addr()) && (it->first < sect->addr()+sect->size()) ) {
1842 pint_t ehAtomAddress = it->first;
1843 BaseAtom* ehAtom = it->second;
1844 const char* ehName = ehAtom->getName();
1845 if ( (ehName != NULL) && (strcmp(&ehName[strlen(ehName)-3], ".eh") == 0) ) {
1846 makeReferenceToEH(ehName, ehAtomAddress, sect);
1847 // make EH symbol static so linker does not try to coalesce
1848 if ( fOptions.fForFinalLinkedImage )
1849 ehAtom->setScope(ObjectFile::Atom::scopeTranslationUnit);
1850 // if it has a reference to a LSDA, add a group reference
1851 std::vector<class ObjectFile::Reference*>& ehrefs = ehAtom->getReferences();
1852 // all FDE's have at least 2 references (to CIE and to function)
1853 if ( ehrefs.size() > 2 ) {
1854 // a third reference means there is a LSDA
1855 ObjectFile::Atom* lsdaAtom = NULL;
1856 for (std::vector<ObjectFile::Reference*>::iterator rit=ehrefs.begin(); rit != ehrefs.end(); rit++) {
1857 ObjectFile::Reference* ref = *rit;
1858 switch ( ref->getFixUpOffset() ) {
1859 case 4:
1860 case 8:
1861 // these are CIE and function references
1862 break;
1863 default:
1864 // this is LSDA reference
1865 lsdaAtom = &ref->getTarget();
1866 }
1867 }
1868 if ( lsdaAtom != NULL ) {
1869 new Reference<A>(A::kGroupSubordinate, AtomAndOffset(ehAtom), AtomAndOffset(lsdaAtom));
1870 }
1871 }
1872 }
1873 }
1874 }
1875 }
1876 }
1877
1878 // add command line aliases
1879 for(std::vector<ObjectFile::ReaderOptions::AliasPair>::const_iterator it = fOptions.fAliases.begin(); it != fOptions.fAliases.end(); ++it) {
1880 BaseAtom* target = this->findAtomByName(it->realName);
1881 if ( (target != NULL) && target->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn )
1882 fAtoms.push_back(new SymbolAliasAtom<A>(it->alias, NULL, *target));
1883 }
1884
1885 // add dtrace probe locations
1886 if ( fHasDTraceProbes ) {
1887 for (uint32_t i=0; i < fSymbolCount; ++i) {
1888 const macho_nlist<P>& sym = fSymbols[i];
1889 if ( (sym.n_type() & N_STAB) == 0 ) {
1890 if ( (sym.n_type() & N_TYPE) == N_SECT ) {
1891 const char* symbolName = &fStrings[sym.n_strx()];
1892 if ( strncmp(symbolName, "__dtrace_probe$", 15) == 0 ) {
1893 //fprintf(stderr, "adding dtrace probe at 0x%08llX %s\n", sym.n_value(), symbolName);
1894 makeByNameReference(A::kDtraceProbe, sym.n_value(), symbolName, 0);
1895 }
1896 }
1897 }
1898 }
1899 }
1900
1901 // turn indirect symbols int SymbolAliasAtom
1902 if ( fHaveIndirectSymbols ) {
1903 for (uint32_t i=0; i < fSymbolCount; ++i) {
1904 const macho_nlist<P>& sym = fSymbols[i];
1905 if ( (sym.n_type() & N_STAB) == 0 ) {
1906 if ( (sym.n_type() & N_TYPE) == N_INDR ) {
1907 const char* aliasName = &fStrings[sym.n_strx()];
1908 const char* targetName = &fStrings[sym.n_value()];
1909 //fprintf(stderr, "found alias %s for %s\n", aliasName, targetName);
1910 BaseAtom* target = this->findAtomByName(targetName);
1911 // only currently support N_INDR based aliases to something in the same .o file
1912 if ( target != NULL ) {
1913 fAtoms.push_back(new SymbolAliasAtom<A>(aliasName, &sym, *target));
1914 //fprintf(stderr, "creating alias %s for %s\n", aliasName, targetName);
1915 }
1916 }
1917 }
1918 }
1919 }
1920
1921 //for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
1922 // fprintf(stderr, "[0x%0X -> 0x%0llX) : %s\n", it->first, it->first+it->second->getSize(), it->second->getDisplayName());
1923 //}
1924
1925 // add translation unit info from dwarf
1926 uint64_t stmtList;
1927 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
1928 // compiler sometimes emits emtpty dwarf sections when there is no debug info, skip those
1929 if ( (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
1930 if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) {
1931 // if can't parse dwarf, warn and give up
1932 fDwarfTranslationUnitFile = NULL;
1933 fDwarfTranslationUnitDir = NULL;
1934 warning("can't parse dwarf compilation unit info in %s", this->getPath());
1935 fDebugInfo = kDebugInfoNone;
1936 }
1937 }
1938 }
1939
1940 // add line number info to atoms from dwarf
1941 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
1942 // file with just data will have no __debug_line info
1943 if ( (fDwarfDebugLineSect != NULL) && (fDwarfDebugLineSect->size() != 0) && (fAddrToAtom.size() != 0)
1944 && (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
1945 // validate stmt_list
1946 if ( (stmtList != (uint64_t)-1) && (stmtList < fDwarfDebugLineSect->size()) ) {
1947 const uint8_t* debug_line = (uint8_t*)(fHeader) + fDwarfDebugLineSect->offset();
1948 if ( debug_line != NULL ) {
1949 struct line_reader_data* lines = line_open(&debug_line[stmtList],
1950 fDwarfDebugLineSect->size() - stmtList, E::little_endian);
1951 struct line_info result;
1952 ObjectFile::Atom* curAtom = NULL;
1953 uint32_t curAtomOffset = 0;
1954 uint32_t curAtomAddress = 0;
1955 uint32_t curAtomSize = 0;
1956 while ( line_next (lines, &result, line_stop_pc) ) {
1957 //fprintf(stderr, "curAtom=%p, result.pc=0x%llX, result.line=%llu, result.end_of_sequence=%d, curAtomAddress=0x%X, curAtomSize=0x%X\n",
1958 // curAtom, result.pc, result.line, result.end_of_sequence, curAtomAddress, curAtomSize);
1959 // work around weird debug line table compiler generates if no functions in __text section
1960 if ( (curAtom == NULL) && (result.pc == 0) && result.end_of_sequence && (result.file == 1))
1961 continue;
1962 // for performance, see if in next pc is in current atom
1963 if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) {
1964 curAtomOffset = result.pc - curAtomAddress;
1965 }
1966 // or pc at end of current atom
1967 else if ( result.end_of_sequence && (curAtom != NULL) && (result.pc == (curAtomAddress+curAtomSize)) ) {
1968 curAtomOffset = result.pc - curAtomAddress;
1969 }
1970 else {
1971 // do slow look up of atom by address
1972 AtomAndOffset ao = this->findAtomAndOffset(result.pc);
1973 curAtom = ao.atom;
1974 if ( curAtom == NULL )
1975 break; // file has line info but no functions
1976 if ( result.end_of_sequence && (curAtomAddress+curAtomSize < result.pc) ) {
1977 // a one line function can be returned by line_next() as one entry with pc at end of blob
1978 // look for alt atom starting at end of previous atom
1979 uint32_t previousEnd = curAtomAddress+curAtomSize;
1980 AtomAndOffset alt = this->findAtomAndOffset(previousEnd);
1981 if ( result.pc <= previousEnd - alt.offset + alt.atom->getSize() ) {
1982 curAtom = alt.atom;
1983 curAtomOffset = alt.offset;
1984 curAtomAddress = previousEnd - alt.offset;
1985 curAtomSize = curAtom->getSize();
1986 }
1987 else {
1988 curAtomOffset = ao.offset;
1989 curAtomAddress = result.pc - ao.offset;
1990 curAtomSize = curAtom->getSize();
1991 }
1992 }
1993 else {
1994 curAtomOffset = ao.offset;
1995 curAtomAddress = result.pc - ao.offset;
1996 curAtomSize = curAtom->getSize();
1997 }
1998 }
1999 const char* filename;
2000 std::map<uint32_t,const char*>::iterator pos = fDwarfIndexToFile.find(result.file);
2001 if ( pos == fDwarfIndexToFile.end() ) {
2002 filename = line_file(lines, result.file);
2003 fDwarfIndexToFile[result.file] = filename;
2004 }
2005 else {
2006 filename = pos->second;
2007 }
2008 ObjectFile::LineInfo info;
2009 info.atomOffset = curAtomOffset;
2010 info.fileName = filename;
2011 info.lineNumber = result.line;
2012 //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n",
2013 // result.pc, result.line, filename, curAtom->getDisplayName(), curAtomSize, result.end_of_sequence);
2014 ((BaseAtom*)curAtom)->addLineInfo(info);
2015 if ( result.end_of_sequence ) {
2016 curAtom = NULL;
2017 }
2018 }
2019 line_free(lines);
2020 }
2021 else {
2022 warning("could not parse dwarf line number info in %s", this->getPath());
2023 }
2024 }
2025 }
2026 }
2027
2028 // if no dwarf, try processing stabs debugging info
2029 if ( (fDebugInfo == kDebugInfoNone) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
2030 // scan symbol table for stabs entries
2031 fStabs.reserve(fSymbolCount); // reduce re-allocations
2032 BaseAtom* currentAtom = NULL;
2033 pint_t currentAtomAddress = 0;
2034 enum { start, inBeginEnd, inFun } state = start;
2035 for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
2036 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
2037 bool useStab = true;
2038 uint8_t type = sym->n_type();
2039 const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL;
2040 if ( (type & N_STAB) != 0 ) {
2041 fDebugInfo = (fHasUUID ? kDebugInfoStabsUUID : kDebugInfoStabs);
2042 Stab stab;
2043 stab.atom = NULL;
2044 stab.type = type;
2045 stab.other = sym->n_sect();
2046 stab.desc = sym->n_desc();
2047 stab.value = sym->n_value();
2048 stab.string = NULL;
2049 switch (state) {
2050 case start:
2051 switch (type) {
2052 case N_BNSYM:
2053 // beginning of function block
2054 state = inBeginEnd;
2055 // fall into case to lookup atom by addresss
2056 case N_LCSYM:
2057 case N_STSYM:
2058 currentAtomAddress = sym->n_value();
2059 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2060 if ( currentAtom != NULL ) {
2061 stab.atom = currentAtom;
2062 stab.string = symString;
2063 }
2064 else {
2065 fprintf(stderr, "can't find atom for stabs BNSYM at %08llX in %s",
2066 (uint64_t)sym->n_value(), path);
2067 }
2068 break;
2069 case N_SO:
2070 case N_OSO:
2071 case N_OPT:
2072 case N_LSYM:
2073 case N_RSYM:
2074 case N_PSYM:
2075 // not associated with an atom, just copy
2076 stab.string = symString;
2077 break;
2078 case N_GSYM:
2079 {
2080 // n_value field is NOT atom address ;-(
2081 // need to find atom by name match
2082 const char* colon = strchr(symString, ':');
2083 if ( colon != NULL ) {
2084 // build underscore leading name
2085 int nameLen = colon - symString;
2086 char symName[nameLen+2];
2087 strlcpy(&symName[1], symString, nameLen+1);
2088 symName[0] = '_';
2089 symName[nameLen+1] = '\0';
2090 currentAtom = findAtomByName(symName);
2091 if ( currentAtom != NULL ) {
2092 stab.atom = currentAtom;
2093 stab.string = symString;
2094 }
2095 }
2096 else {
2097 // might be a debug-note without trailing :G()
2098 currentAtom = findAtomByName(symString);
2099 if ( currentAtom != NULL ) {
2100 stab.atom = currentAtom;
2101 stab.string = symString;
2102 }
2103 }
2104 if ( stab.atom == NULL ) {
2105 warning("can't find atom for N_GSYM stabs %s in %s", symString, path);
2106 useStab = false;
2107 }
2108 break;
2109 }
2110 case N_FUN:
2111 // old style stabs without BNSYM
2112 state = inFun;
2113 currentAtomAddress = sym->n_value();
2114 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2115 if ( currentAtom != NULL ) {
2116 stab.atom = currentAtom;
2117 stab.string = symString;
2118 }
2119 else {
2120 warning("can't find atom for stabs FUN at %08llX in %s",
2121 (uint64_t)currentAtomAddress, path);
2122 }
2123 break;
2124 case N_SOL:
2125 case N_SLINE:
2126 stab.string = symString;
2127 // old stabs
2128 break;
2129 case N_BINCL:
2130 case N_EINCL:
2131 case N_EXCL:
2132 stab.string = symString;
2133 // -gfull built .o file
2134 break;
2135 default:
2136 warning("unknown stabs type 0x%X in %s", type, path);
2137 }
2138 break;
2139 case inBeginEnd:
2140 stab.atom = currentAtom;
2141 switch (type) {
2142 case N_ENSYM:
2143 state = start;
2144 currentAtom = NULL;
2145 break;
2146 case N_LCSYM:
2147 case N_STSYM:
2148 {
2149 BaseAtom* nestedAtom = (BaseAtom*)this->findAtomAndOffset(sym->n_value()).atom;
2150 if ( nestedAtom != NULL ) {
2151 stab.atom = nestedAtom;
2152 stab.string = symString;
2153 }
2154 else {
2155 warning("can't find atom for stabs 0x%X at %08llX in %s",
2156 type, (uint64_t)sym->n_value(), path);
2157 }
2158 break;
2159 }
2160 case N_LBRAC:
2161 case N_RBRAC:
2162 case N_SLINE:
2163 // adjust value to be offset in atom
2164 stab.value -= currentAtomAddress;
2165 default:
2166 stab.string = symString;
2167 break;
2168 }
2169 break;
2170 case inFun:
2171 switch (type) {
2172 case N_FUN:
2173 if ( sym->n_sect() != 0 ) {
2174 // found another start stab, must be really old stabs...
2175 currentAtomAddress = sym->n_value();
2176 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2177 if ( currentAtom != NULL ) {
2178 stab.atom = currentAtom;
2179 stab.string = symString;
2180 }
2181 else {
2182 warning("can't find atom for stabs FUN at %08llX in %s",
2183 (uint64_t)currentAtomAddress, path);
2184 }
2185 }
2186 else {
2187 // found ending stab, switch back to start state
2188 stab.string = symString;
2189 stab.atom = currentAtom;
2190 state = start;
2191 currentAtom = NULL;
2192 }
2193 break;
2194 case N_LBRAC:
2195 case N_RBRAC:
2196 case N_SLINE:
2197 // adjust value to be offset in atom
2198 stab.value -= currentAtomAddress;
2199 stab.atom = currentAtom;
2200 break;
2201 case N_SO:
2202 stab.string = symString;
2203 state = start;
2204 break;
2205 default:
2206 stab.atom = currentAtom;
2207 stab.string = symString;
2208 break;
2209 }
2210 break;
2211 }
2212 // add to list of stabs for this .o file
2213 if ( useStab )
2214 fStabs.push_back(stab);
2215 }
2216 }
2217 }
2218
2219 #if 0
2220 // special case precompiled header .o file (which has no content) to have one empty atom
2221 if ( fAtoms.size() == 0 ) {
2222 int pathLen = strlen(path);
2223 if ( (pathLen > 6) && (strcmp(&path[pathLen-6], ".gch.o")==0) ) {
2224 ObjectFile::Atom* phony = new AnonymousAtom<A>(*this, (uint32_t)0);
2225 //phony->fSynthesizedName = ".gch.o";
2226 fAtoms.push_back(phony);
2227 }
2228 }
2229 #endif
2230
2231 // sort all atoms by address
2232 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
2233
2234 // set ordinal and sort references in each atom
2235 uint32_t index = fOrdinalBase;
2236 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
2237 BaseAtom* atom = (BaseAtom*)(*it);
2238 atom->setOrdinal(index++);
2239 atom->sortReferences();
2240 }
2241
2242 }
2243
2244
2245 template <>
2246 void Reader<ppc>::setCpuConstraint(uint32_t cpusubtype)
2247 {
2248 switch (cpusubtype) {
2249 case CPU_SUBTYPE_POWERPC_ALL:
2250 case CPU_SUBTYPE_POWERPC_750:
2251 case CPU_SUBTYPE_POWERPC_7400:
2252 case CPU_SUBTYPE_POWERPC_7450:
2253 case CPU_SUBTYPE_POWERPC_970:
2254 fCpuConstraint = cpusubtype;
2255 break;
2256 default:
2257 warning("unknown ppc subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
2258 fCpuConstraint = CPU_SUBTYPE_POWERPC_ALL;
2259 break;
2260 }
2261 }
2262
2263 template <>
2264 void Reader<arm>::setCpuConstraint(uint32_t cpusubtype)
2265 {
2266 switch (cpusubtype) {
2267 case CPU_SUBTYPE_ARM_ALL:
2268 case CPU_SUBTYPE_ARM_V4T:
2269 case CPU_SUBTYPE_ARM_V5TEJ:
2270 case CPU_SUBTYPE_ARM_V6:
2271 case CPU_SUBTYPE_ARM_XSCALE:
2272 fCpuConstraint = cpusubtype;
2273 break;
2274 default:
2275 warning("unknown arm subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
2276 fCpuConstraint = CPU_SUBTYPE_ARM_ALL;
2277 break;
2278 }
2279 }
2280
2281 template <typename A>
2282 void Reader<A>::setCpuConstraint(uint32_t cpusubtype)
2283 {
2284 // no cpu sub types for this architecture
2285 }
2286
2287 template <>
2288 uint32_t Reader<ppc>::updateCpuConstraint(uint32_t previous)
2289 {
2290 switch ( previous ) {
2291 case CPU_SUBTYPE_POWERPC_ALL:
2292 return fCpuConstraint;
2293 break;
2294 case CPU_SUBTYPE_POWERPC_750:
2295 if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_7400 ||
2296 fCpuConstraint == CPU_SUBTYPE_POWERPC_7450 ||
2297 fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
2298 return fCpuConstraint;
2299 break;
2300 case CPU_SUBTYPE_POWERPC_7400:
2301 case CPU_SUBTYPE_POWERPC_7450:
2302 if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
2303 return fCpuConstraint;
2304 break;
2305 case CPU_SUBTYPE_POWERPC_970:
2306 // G5 can run everything
2307 break;
2308 default:
2309 throw "Unhandled PPC cpu subtype!";
2310 break;
2311 }
2312 return previous;
2313 }
2314
2315
2316
2317 template <>
2318 uint32_t Reader<arm>::updateCpuConstraint(uint32_t previous)
2319 {
2320 switch (previous) {
2321 case CPU_SUBTYPE_ARM_ALL:
2322 return fCpuConstraint;
2323 break;
2324 case CPU_SUBTYPE_ARM_V5TEJ:
2325 // v6 and xscale are more constrained than previous file (v5), so use it
2326 if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
2327 || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
2328 return fCpuConstraint;
2329 break;
2330 case CPU_SUBTYPE_ARM_V4T:
2331 // v5, v6, and xscale are more constrained than previous file (v4t), so use it
2332 if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
2333 || (fCpuConstraint == CPU_SUBTYPE_ARM_V5TEJ)
2334 || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
2335 return fCpuConstraint;
2336 break;
2337 case CPU_SUBTYPE_ARM_V6:
2338 // v6 can run everything except xscale
2339 if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE )
2340 throw "can't mix xscale and v6 code";
2341 break;
2342 case CPU_SUBTYPE_ARM_XSCALE:
2343 // xscale can run everything except v6
2344 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V6 )
2345 throw "can't mix xscale and v6 code";
2346 break;
2347 default:
2348 throw "Unhandled ARM cpu subtype!";
2349 }
2350 return previous;
2351 }
2352
2353 template <typename A>
2354 uint32_t Reader<A>::updateCpuConstraint(uint32_t current)
2355 {
2356 // no cpu sub types for this architecture
2357 return current;
2358 }
2359
2360 template <typename A>
2361 void Reader<A>::addDtraceExtraInfos(uint32_t probeAddr, const char* providerName)
2362 {
2363 // for every ___dtrace_stability$* and ___dtrace_typedefs$* undefine with
2364 // a matching provider name, add a by-name kDtraceTypeReference at probe site
2365 const char* dollar = strchr(providerName, '$');
2366 if ( dollar != NULL ) {
2367 int providerNameLen = dollar-providerName+1;
2368 for ( std::vector<const char*>::iterator it = fDtraceProviderInfo.begin(); it != fDtraceProviderInfo.end(); ++it) {
2369 const char* typeDollar = strchr(*it, '$');
2370 if ( typeDollar != NULL ) {
2371 if ( strncmp(typeDollar+1, providerName, providerNameLen) == 0 ) {
2372 makeByNameReference(A::kDtraceTypeReference, probeAddr, *it, 0);
2373 }
2374 }
2375 }
2376 }
2377 }
2378
2379
2380 template <>
2381 void Reader<x86_64>::validSectionType(uint8_t type)
2382 {
2383 switch ( type ) {
2384 case S_SYMBOL_STUBS:
2385 throw "symbol_stub sections not valid in x86_64 object files";
2386 case S_LAZY_SYMBOL_POINTERS:
2387 throw "lazy pointer sections not valid in x86_64 object files";
2388 case S_NON_LAZY_SYMBOL_POINTERS:
2389 throw "non lazy pointer sections not valid in x86_64 object files";
2390 }
2391 }
2392
2393 template <typename A>
2394 void Reader<A>::validSectionType(uint8_t type)
2395 {
2396 }
2397
2398 template <typename A>
2399 bool Reader<A>::getTranslationUnitSource(const char** dir, const char** name) const
2400 {
2401 if ( fDebugInfo == kDebugInfoDwarf ) {
2402 *dir = fDwarfTranslationUnitDir;
2403 *name = fDwarfTranslationUnitFile;
2404 return (fDwarfTranslationUnitFile != NULL);
2405 }
2406 return false;
2407 }
2408
2409 template <typename A>
2410 BaseAtom* Reader<A>::findAtomByName(const char* name)
2411 {
2412 // first search the more important atoms
2413 for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
2414 const char* atomName = it->second->getName();
2415 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
2416 return it->second;
2417 }
2418 }
2419 // try all atoms, because this might have been a tentative definition
2420 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
2421 BaseAtom* atom = (BaseAtom*)(*it);
2422 const char* atomName = atom->getName();
2423 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
2424 return atom;
2425 }
2426 }
2427 return NULL;
2428 }
2429
2430 template <typename A>
2431 Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t toAddr)
2432 {
2433 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toAddr));
2434 }
2435
2436 template <typename A>
2437 Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr)
2438 {
2439 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toAddr));
2440 }
2441
2442 template <typename A>
2443 Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr)
2444 {
2445 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toBaseAddr, toAddr));
2446 }
2447
2448 template <typename A>
2449 Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr)
2450 {
2451 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toBaseAddr, toAddr));
2452 }
2453
2454 template <typename A>
2455 Reference<A>* Reader<A>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
2456 {
2457 return new Reference<A>(kind, findAtomAndOffset(atAddr), toName, toOffset);
2458 }
2459
2460 template <typename A>
2461 Reference<A>* Reader<A>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
2462 {
2463 // add a direct reference from function atom to its eh frame atom
2464 const uint8_t* ehContent = (const uint8_t*)(fHeader) + ehAtomAddress - ehSect->addr() + ehSect->offset();
2465 int32_t deltaMinus8 = P::getP(*(pint_t*)(&ehContent[8])); // offset 8 in eh info is delta to function
2466 pint_t funcAddr = ehAtomAddress + deltaMinus8 + 8;
2467 return makeReference(A::kGroupSubordinate, funcAddr, ehAtomAddress);
2468 }
2469
2470
2471 template <>
2472 Reference<x86_64>* Reader<x86_64>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
2473 {
2474 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
2475 // instead check scope of target
2476 BaseAtom* target = findAtomByName(toName);
2477 if ( (target != NULL) && (target->getScope() == ObjectFile::Atom::scopeTranslationUnit) )
2478 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), AtomAndOffset(target, toOffset));
2479 else
2480 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), toName, toOffset);
2481 }
2482
2483 template <>
2484 Reference<x86_64>* Reader<x86_64>::makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset)
2485 {
2486 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
2487 // instead check scope of target
2488 const char* symbolName = &fStrings[toSymbol->n_strx()];
2489 if ( ((toSymbol->n_type() & N_TYPE) == N_SECT) && (((toSymbol->n_type() & N_EXT) == 0) || (symbolName[0] == 'L')) )
2490 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toSymbol->n_value(), toSymbol->n_value()+toOffset));
2491 else
2492 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), symbolName, toOffset);
2493 }
2494
2495
2496 template <>
2497 Reference<x86_64>* Reader<x86_64>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
2498 {
2499 // add a direct reference from function atom to its eh frame atom
2500 // for x86_64 the __eh_frame section contains the addends, so need to use relocs to find target
2501 uint32_t ehAtomDeltaSectionOffset = ehAtomAddress + 8 - ehSect->addr(); // offset 8 in eh info is delta to function
2502 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + ehSect->reloff());
2503 const macho_relocation_info<P>* relocsEnd = &relocs[ehSect->nreloc()];
2504 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
2505 if ( (reloc->r_address() == ehAtomDeltaSectionOffset) && (reloc->r_type() == X86_64_RELOC_UNSIGNED) ) {
2506 pint_t funcAddr = fSymbols[reloc->r_symbolnum()].n_value();
2507 return makeReference(x86_64::kGroupSubordinate, funcAddr, ehAtomAddress);
2508 }
2509 }
2510 warning("can't find matching function for eh symbol %s", ehName);
2511 return NULL;
2512 }
2513
2514
2515 template <typename A>
2516 AtomAndOffset Reader<A>::findAtomAndOffset(pint_t addr)
2517 {
2518 // STL has no built-in for "find largest key that is same or less than"
2519 typename AddrToAtomMap::iterator it = fAddrToAtom.upper_bound(addr);
2520 // if no atoms up to this address return none found
2521 if ( it == fAddrToAtom.begin() )
2522 return AtomAndOffset(NULL);
2523 // otherwise upper_bound gets us next key, so we back up one
2524 --it;
2525 AtomAndOffset result;
2526 result.atom = it->second;
2527 result.offset = addr - it->first;
2528 //fprintf(stderr, "findAtomAndOffset(0x%0llX) ==> %s (0x%0llX -> 0x%0llX)\n",
2529 // (uint64_t)addr, result.atom->getDisplayName(), (uint64_t)it->first, it->first+result.atom->getSize());
2530 return result;
2531 }
2532
2533 // "scattered" relocations enable you to offset into an atom past the end of it
2534 // baseAddr is the address of the target atom,
2535 // realAddr is the points into it
2536 template <typename A>
2537 AtomAndOffset Reader<A>::findAtomAndOffset(pint_t baseAddr, pint_t realAddr)
2538 {
2539 typename AddrToAtomMap::iterator it = fAddrToAtom.find(baseAddr);
2540 if ( it != fAddrToAtom.end() ) {
2541 AtomAndOffset result;
2542 result.atom = it->second;
2543 result.offset = realAddr - it->first;
2544 //fprintf(stderr, "findAtomAndOffset(0x%08X, 0x%08X) => %s + 0x%08X\n", baseAddr, realAddr, result.atom->getDisplayName(), result.offset);
2545 return result;
2546 }
2547 // getting here means we have a scattered relocation to an address without a label
2548 // we should never get here...
2549 // one case we do get here is because sometimes the compiler generates non-lazy pointers in the __data section
2550 return findAtomAndOffset(realAddr);
2551 }
2552
2553
2554 /* Skip over a LEB128 value (signed or unsigned). */
2555 static void
2556 skip_leb128 (const uint8_t ** offset, const uint8_t * end)
2557 {
2558 while (*offset != end && **offset >= 0x80)
2559 (*offset)++;
2560 if (*offset != end)
2561 (*offset)++;
2562 }
2563
2564 /* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow
2565 or error. On overflow, skip past the rest of the uleb128. */
2566 static uint64_t
2567 read_uleb128 (const uint8_t ** offset, const uint8_t * end)
2568 {
2569 uint64_t result = 0;
2570 int bit = 0;
2571
2572 do {
2573 uint64_t b;
2574
2575 if (*offset == end)
2576 return (uint64_t) -1;
2577
2578 b = **offset & 0x7f;
2579
2580 if (bit >= 64 || b << bit >> bit != b)
2581 result = (uint64_t) -1;
2582 else
2583 result |= b << bit, bit += 7;
2584 } while (*(*offset)++ >= 0x80);
2585 return result;
2586 }
2587
2588
2589 /* Skip over a DWARF attribute of form FORM. */
2590 template <typename A>
2591 bool Reader<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form,
2592 uint8_t addr_size, bool dwarf64)
2593 {
2594 int64_t sz=0;
2595
2596 switch (form)
2597 {
2598 case DW_FORM_addr:
2599 sz = addr_size;
2600 break;
2601
2602 case DW_FORM_block2:
2603 if (end - *offset < 2)
2604 return false;
2605 sz = 2 + A::P::E::get16(*(uint16_t*)offset);
2606 break;
2607
2608 case DW_FORM_block4:
2609 if (end - *offset < 4)
2610 return false;
2611 sz = 2 + A::P::E::get32(*(uint32_t*)offset);
2612 break;
2613
2614 case DW_FORM_data2:
2615 case DW_FORM_ref2:
2616 sz = 2;
2617 break;
2618
2619 case DW_FORM_data4:
2620 case DW_FORM_ref4:
2621 sz = 4;
2622 break;
2623
2624 case DW_FORM_data8:
2625 case DW_FORM_ref8:
2626 sz = 8;
2627 break;
2628
2629 case DW_FORM_string:
2630 while (*offset != end && **offset)
2631 ++*offset;
2632 case DW_FORM_data1:
2633 case DW_FORM_flag:
2634 case DW_FORM_ref1:
2635 sz = 1;
2636 break;
2637
2638 case DW_FORM_block:
2639 sz = read_uleb128 (offset, end);
2640 break;
2641
2642 case DW_FORM_block1:
2643 if (*offset == end)
2644 return false;
2645 sz = 1 + **offset;
2646 break;
2647
2648 case DW_FORM_sdata:
2649 case DW_FORM_udata:
2650 case DW_FORM_ref_udata:
2651 skip_leb128 (offset, end);
2652 return true;
2653
2654 case DW_FORM_strp:
2655 case DW_FORM_ref_addr:
2656 sz = dwarf64 ? 8 : 4;
2657 break;
2658
2659 default:
2660 return false;
2661 }
2662 if (end - *offset < sz)
2663 return false;
2664 *offset += sz;
2665 return true;
2666 }
2667
2668 // Look at the compilation unit DIE and determine
2669 // its NAME, compilation directory (in COMP_DIR) and its
2670 // line number information offset (in STMT_LIST). NAME and COMP_DIR
2671 // may be NULL (especially COMP_DIR) if they are not in the .o file;
2672 // STMT_LIST will be (uint64_t) -1.
2673 //
2674 // At present this assumes that there's only one compilation unit DIE.
2675 //
2676 template <typename A>
2677 bool Reader<A>::read_comp_unit(const char ** name, const char ** comp_dir,
2678 uint64_t *stmt_list)
2679 {
2680 const uint8_t * debug_info;
2681 const uint8_t * debug_abbrev;
2682 const uint8_t * di;
2683 const uint8_t * da;
2684 const uint8_t * end;
2685 const uint8_t * enda;
2686 uint64_t sz;
2687 uint16_t vers;
2688 uint64_t abbrev_base;
2689 uint64_t abbrev;
2690 uint8_t address_size;
2691 bool dwarf64;
2692
2693 *name = NULL;
2694 *comp_dir = NULL;
2695 *stmt_list = (uint64_t) -1;
2696
2697 if ( (fDwarfDebugInfoSect == NULL) || (fDwarfDebugAbbrevSect == NULL) )
2698 return false;
2699
2700 debug_info = (uint8_t*)(fHeader) + fDwarfDebugInfoSect->offset();
2701 debug_abbrev = (uint8_t*)(fHeader) + fDwarfDebugAbbrevSect->offset();
2702 di = debug_info;
2703
2704 if (fDwarfDebugInfoSect->size() < 12)
2705 /* Too small to be a real debug_info section. */
2706 return false;
2707 sz = A::P::E::get32(*(uint32_t*)di);
2708 di += 4;
2709 dwarf64 = sz == 0xffffffff;
2710 if (dwarf64)
2711 sz = A::P::E::get64(*(uint64_t*)di), di += 8;
2712 else if (sz > 0xffffff00)
2713 /* Unknown dwarf format. */
2714 return false;
2715
2716 /* Verify claimed size. */
2717 if (sz + (di - debug_info) > fDwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11))
2718 return false;
2719
2720 vers = A::P::E::get16(*(uint16_t*)di);
2721 if (vers < 2 || vers > 3)
2722 /* DWARF version wrong for this code.
2723 Chances are we could continue anyway, but we don't know for sure. */
2724 return false;
2725 di += 2;
2726
2727 /* Find the debug_abbrev section. */
2728 abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di);
2729 di += dwarf64 ? 8 : 4;
2730
2731 if (abbrev_base > fDwarfDebugAbbrevSect->size())
2732 return false;
2733 da = debug_abbrev + abbrev_base;
2734 enda = debug_abbrev + fDwarfDebugAbbrevSect->size();
2735
2736 address_size = *di++;
2737
2738 /* Find the abbrev number we're looking for. */
2739 end = di + sz;
2740 abbrev = read_uleb128 (&di, end);
2741 if (abbrev == (uint64_t) -1)
2742 return false;
2743
2744 /* Skip through the debug_abbrev section looking for that abbrev. */
2745 for (;;)
2746 {
2747 uint64_t this_abbrev = read_uleb128 (&da, enda);
2748 uint64_t attr;
2749
2750 if (this_abbrev == abbrev)
2751 /* This is almost always taken. */
2752 break;
2753 skip_leb128 (&da, enda); /* Skip the tag. */
2754 if (da == enda)
2755 return false;
2756 da++; /* Skip the DW_CHILDREN_* value. */
2757
2758 do {
2759 attr = read_uleb128 (&da, enda);
2760 skip_leb128 (&da, enda);
2761 } while (attr != 0 && attr != (uint64_t) -1);
2762 if (attr != 0)
2763 return false;
2764 }
2765
2766 /* Check that the abbrev is one for a DW_TAG_compile_unit. */
2767 if (read_uleb128 (&da, enda) != DW_TAG_compile_unit)
2768 return false;
2769 if (da == enda)
2770 return false;
2771 da++; /* Skip the DW_CHILDREN_* value. */
2772
2773 /* Now, go through the DIE looking for DW_AT_name,
2774 DW_AT_comp_dir, and DW_AT_stmt_list. */
2775 for (;;)
2776 {
2777 uint64_t attr = read_uleb128 (&da, enda);
2778 uint64_t form = read_uleb128 (&da, enda);
2779
2780 if (attr == (uint64_t) -1)
2781 return false;
2782 else if (attr == 0)
2783 return true;
2784
2785 if (form == DW_FORM_indirect)
2786 form = read_uleb128 (&di, end);
2787
2788 if (attr == DW_AT_name && form == DW_FORM_string)
2789 *name = (const char *) di;
2790 else if (attr == DW_AT_comp_dir && form == DW_FORM_string)
2791 *comp_dir = (const char *) di;
2792 /* Really we should support DW_FORM_strp here, too, but
2793 there's usually no reason for the producer to use that form
2794 for the DW_AT_name and DW_AT_comp_dir attributes. */
2795 else if (attr == DW_AT_stmt_list && form == DW_FORM_data4)
2796 *stmt_list = A::P::E::get32(*(uint32_t*)di);
2797 else if (attr == DW_AT_stmt_list && form == DW_FORM_data8)
2798 *stmt_list = A::P::E::get64(*(uint64_t*)di);
2799 if (! skip_form (&di, end, form, address_size, dwarf64))
2800 return false;
2801 }
2802 }
2803
2804 template <typename A>
2805 const char* Reader<A>::assureFullPath(const char* path)
2806 {
2807 if ( path[0] == '/' )
2808 return path;
2809 char cwdbuff[MAXPATHLEN];
2810 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
2811 char* result;
2812 asprintf(&result, "%s/%s", cwdbuff, path);
2813 if ( result != NULL )
2814 return result;
2815 }
2816 return path;
2817 }
2818
2819
2820 //
2821 //
2822 // To implement architecture xxx, you must write template specializations for the following six methods:
2823 // Reader<xxx>::validFile()
2824 // Reader<xxx>::addRelocReference()
2825 // Reference<xxx>::getDescription()
2826 //
2827 //
2828
2829
2830 template <>
2831 bool Reader<ppc>::validFile(const uint8_t* fileContent)
2832 {
2833 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2834 if ( header->magic() != MH_MAGIC )
2835 return false;
2836 if ( header->cputype() != CPU_TYPE_POWERPC )
2837 return false;
2838 if ( header->filetype() != MH_OBJECT )
2839 return false;
2840 return true;
2841 }
2842
2843 template <>
2844 bool Reader<ppc64>::validFile(const uint8_t* fileContent)
2845 {
2846 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2847 if ( header->magic() != MH_MAGIC_64 )
2848 return false;
2849 if ( header->cputype() != CPU_TYPE_POWERPC64 )
2850 return false;
2851 if ( header->filetype() != MH_OBJECT )
2852 return false;
2853 return true;
2854 }
2855
2856 template <>
2857 bool Reader<x86>::validFile(const uint8_t* fileContent)
2858 {
2859 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2860 if ( header->magic() != MH_MAGIC )
2861 return false;
2862 if ( header->cputype() != CPU_TYPE_I386 )
2863 return false;
2864 if ( header->filetype() != MH_OBJECT )
2865 return false;
2866 return true;
2867 }
2868
2869 template <>
2870 bool Reader<x86_64>::validFile(const uint8_t* fileContent)
2871 {
2872 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2873 if ( header->magic() != MH_MAGIC_64 )
2874 return false;
2875 if ( header->cputype() != CPU_TYPE_X86_64 )
2876 return false;
2877 if ( header->filetype() != MH_OBJECT )
2878 return false;
2879 return true;
2880 }
2881
2882 template <>
2883 bool Reader<arm>::validFile(const uint8_t* fileContent)
2884 {
2885 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2886 if ( header->magic() != MH_MAGIC )
2887 return false;
2888 if ( header->cputype() != CPU_TYPE_ARM )
2889 return false;
2890 if ( header->filetype() != MH_OBJECT )
2891 return false;
2892 return true;
2893 }
2894
2895 template <typename A>
2896 bool Reader<A>::isWeakImportSymbol(const macho_nlist<P>* sym)
2897 {
2898 return ( ((sym->n_type() & N_TYPE) == N_UNDF) && ((sym->n_desc() & N_WEAK_REF) != 0) );
2899 }
2900
2901 template <>
2902 bool Reader<ppc64>::addRelocReference(const macho_section<ppc64::P>* sect, const macho_relocation_info<ppc64::P>* reloc)
2903 {
2904 return addRelocReference_powerpc(sect, reloc);
2905 }
2906
2907 template <>
2908 bool Reader<ppc>::addRelocReference(const macho_section<ppc::P>* sect, const macho_relocation_info<ppc::P>* reloc)
2909 {
2910 return addRelocReference_powerpc(sect, reloc);
2911 }
2912
2913
2914 //
2915 // ppc and ppc64 both use the same relocations, so process them in one common routine
2916 //
2917 template <typename A>
2918 bool Reader<A>::addRelocReference_powerpc(const macho_section<typename A::P>* sect,
2919 const macho_relocation_info<typename A::P>* reloc)
2920 {
2921 uint32_t srcAddr;
2922 uint32_t dstAddr;
2923 uint32_t* fixUpPtr;
2924 int32_t displacement = 0;
2925 uint32_t instruction = 0;
2926 uint32_t offsetInTarget;
2927 int16_t lowBits;
2928 bool result = false;
2929 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
2930 const macho_relocation_info<P>* nextReloc = &reloc[1];
2931 const char* targetName = NULL;
2932 bool weakImport = false;
2933 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
2934 if ( reloc->r_type() != PPC_RELOC_PAIR )
2935 instruction = BigEndian::get32(*fixUpPtr);
2936 srcAddr = sect->addr() + reloc->r_address();
2937 if ( reloc->r_extern() ) {
2938 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
2939 targetName = &fStrings[targetSymbol->n_strx()];
2940 weakImport = this->isWeakImportSymbol(targetSymbol);
2941 }
2942 switch ( reloc->r_type() ) {
2943 case PPC_RELOC_BR24:
2944 {
2945 if ( (instruction & 0x4C000000) == 0x48000000 ) {
2946 displacement = (instruction & 0x03FFFFFC);
2947 if ( (displacement & 0x02000000) != 0 )
2948 displacement |= 0xFC000000;
2949 }
2950 else {
2951 printf("bad instruction for BR24 reloc");
2952 }
2953 if ( reloc->r_extern() ) {
2954 offsetInTarget = srcAddr + displacement;
2955 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
2956 makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
2957 addDtraceExtraInfos(srcAddr, &targetName[16]);
2958 }
2959 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
2960 makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
2961 addDtraceExtraInfos(srcAddr, &targetName[20]);
2962 }
2963 else if ( weakImport )
2964 makeByNameReference(A::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
2965 else
2966 makeByNameReference(A::kBranch24, srcAddr, targetName, offsetInTarget);
2967 }
2968 else {
2969 dstAddr = srcAddr + displacement;
2970 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
2971 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
2972 targetName = atom->getName();
2973 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
2974 makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
2975 addDtraceExtraInfos(srcAddr, &targetName[16]);
2976 }
2977 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
2978 makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
2979 addDtraceExtraInfos(srcAddr, &targetName[20]);
2980 }
2981 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
2982 && ((AnonymousAtom<A>*)atom)->isWeakImportStub() )
2983 makeReference(A::kBranch24WeakImport, srcAddr, dstAddr);
2984 else
2985 makeReference(A::kBranch24, srcAddr, dstAddr);
2986 }
2987 }
2988 break;
2989 case PPC_RELOC_BR14:
2990 {
2991 displacement = (instruction & 0x0000FFFC);
2992 if ( (displacement & 0x00008000) != 0 )
2993 displacement |= 0xFFFF0000;
2994 if ( reloc->r_extern() ) {
2995 offsetInTarget = srcAddr + displacement;
2996 makeByNameReference(A::kBranch14, srcAddr, targetName, offsetInTarget);
2997 }
2998 else {
2999 dstAddr = srcAddr + displacement;
3000 makeReference(A::kBranch14, srcAddr, dstAddr);
3001 }
3002 }
3003 break;
3004 case PPC_RELOC_PAIR:
3005 // skip, processed by a previous look ahead
3006 break;
3007 case PPC_RELOC_LO16:
3008 {
3009 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
3010 warning("PPC_RELOC_LO16 missing following pair");
3011 break;
3012 }
3013 result = true;
3014 lowBits = (instruction & 0xFFFF);
3015 if ( reloc->r_extern() ) {
3016 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
3017 makeByNameReference(A::kAbsLow16, srcAddr, targetName, offsetInTarget);
3018 }
3019 else {
3020 dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF);
3021 if ( reloc->r_symbolnum() == R_ABS ) {
3022 // find absolute symbol that corresponds to pointerValue
3023 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
3024 if ( pos != fAddrToAbsoluteAtom.end() )
3025 makeByNameReference(A::kAbsLow16, srcAddr, pos->second->getName(), 0);
3026 else
3027 makeReference(A::kAbsLow16, srcAddr, dstAddr);
3028 }
3029 else {
3030 makeReference(A::kAbsLow16, srcAddr, dstAddr);
3031 }
3032 }
3033 }
3034 break;
3035 case PPC_RELOC_LO14:
3036 {
3037 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
3038 warning("PPC_RELOC_LO14 missing following pair");
3039 break;
3040 }
3041 result = true;
3042 lowBits = (instruction & 0xFFFC);
3043 if ( reloc->r_extern() ) {
3044 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
3045 makeByNameReference(A::kAbsLow14, srcAddr, targetName, offsetInTarget);
3046 }
3047 else {
3048 dstAddr = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
3049 if ( reloc->r_symbolnum() == R_ABS ) {
3050 // find absolute symbol that corresponds to pointerValue
3051 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
3052 if ( pos != fAddrToAbsoluteAtom.end() )
3053 makeByNameReference(A::kAbsLow14, srcAddr, pos->second->getName(), 0);
3054 else
3055 makeReference(A::kAbsLow14, srcAddr, dstAddr);
3056 }
3057 else {
3058 makeReference(A::kAbsLow14, srcAddr, dstAddr);
3059 }
3060 }
3061 }
3062 break;
3063 case PPC_RELOC_HI16:
3064 {
3065 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
3066 warning("PPC_RELOC_HI16 missing following pair");
3067 break;
3068 }
3069 result = true;
3070 if ( reloc->r_extern() ) {
3071 offsetInTarget = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
3072 makeByNameReference(A::kAbsHigh16, srcAddr, targetName, offsetInTarget);
3073 }
3074 else {
3075 dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
3076 if ( reloc->r_symbolnum() == R_ABS ) {
3077 // find absolute symbol that corresponds to pointerValue
3078 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
3079 if ( pos != fAddrToAbsoluteAtom.end() )
3080 makeByNameReference(A::kAbsHigh16, srcAddr, pos->second->getName(), 0);
3081 else
3082 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
3083 }
3084 else {
3085 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
3086 }
3087 }
3088 }
3089 break;
3090 case PPC_RELOC_HA16:
3091 {
3092 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
3093 warning("PPC_RELOC_HA16 missing following pair");
3094 break;
3095 }
3096 result = true;
3097 lowBits = (nextReloc->r_address() & 0x0000FFFF);
3098 if ( reloc->r_extern() ) {
3099 offsetInTarget = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
3100 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, targetName, offsetInTarget);
3101 }
3102 else {
3103 dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
3104 if ( reloc->r_symbolnum() == R_ABS ) {
3105 // find absolute symbol that corresponds to pointerValue
3106 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
3107 if ( pos != fAddrToAbsoluteAtom.end() )
3108 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, pos->second->getName(), 0);
3109 else
3110 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
3111 }
3112 else {
3113 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
3114 }
3115 }
3116 }
3117 break;
3118 case PPC_RELOC_VANILLA:
3119 {
3120 pint_t pointerValue = P::getP(*((pint_t*)fixUpPtr));
3121 if ( reloc->r_extern() ) {
3122 if ( weakImport )
3123 makeByNameReference(A::kPointerWeakImport, srcAddr, targetName, pointerValue);
3124 else
3125 makeByNameReference(A::kPointer, srcAddr, targetName, pointerValue);
3126 }
3127 else {
3128 makeReference(A::kPointer, srcAddr, pointerValue);
3129 }
3130 }
3131 break;
3132 case PPC_RELOC_JBSR:
3133 // this is from -mlong-branch codegen. We ignore the jump island and make reference to the real target
3134 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
3135 warning("PPC_RELOC_JBSR missing following pair");
3136 break;
3137 }
3138 fHasLongBranchStubs = true;
3139 result = true;
3140 makeReference(A::kBranch24, srcAddr, nextReloc->r_address());
3141 if ( (instruction & 0x4C000000) == 0x48000000 ) {
3142 displacement = (instruction & 0x03FFFFFC);
3143 if ( (displacement & 0x02000000) != 0 )
3144 displacement |= 0xFC000000;
3145 }
3146 else {
3147 fprintf(stderr, "bad instruction for BR24 reloc");
3148 }
3149 if ( reloc->r_extern() ) {
3150 fprintf(stderr, "PPC_RELOC_JBSR should not be using an external relocation");
3151 }
3152 break;
3153 default:
3154 warning("unknown relocation type %d", reloc->r_type());
3155 }
3156 }
3157 else {
3158 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
3159 srcAddr = sect->addr() + sreloc->r_address();
3160 dstAddr = sreloc->r_value();
3161 uint32_t betterDstAddr;
3162 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
3163 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
3164 const macho_relocation_info<P>* nextReloc = &reloc[1];
3165 // file format allows pair to be scattered or not
3166 bool nextRelocIsPair = false;
3167 uint32_t nextRelocAddress = 0;
3168 uint32_t nextRelocValue = 0;
3169 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
3170 if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
3171 nextRelocIsPair = true;
3172 nextRelocAddress = nextReloc->r_address();
3173 result = true;
3174 }
3175 }
3176 else {
3177 if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
3178 nextRelocIsPair = true;
3179 nextRelocAddress = nextSReloc->r_address();
3180 nextRelocValue = nextSReloc->r_value();
3181 result = true;
3182 }
3183 }
3184 switch (sreloc->r_type()) {
3185 case PPC_RELOC_VANILLA:
3186 {
3187 betterDstAddr = P::getP(*(pint_t*)fixUpPtr);
3188 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
3189 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
3190 makeReferenceWithToBase(A::kPointer, srcAddr, betterDstAddr, dstAddr);
3191 }
3192 break;
3193 case PPC_RELOC_BR14:
3194 {
3195 instruction = BigEndian::get32(*fixUpPtr);
3196 displacement = (instruction & 0x0000FFFC);
3197 if ( (displacement & 0x00008000) != 0 )
3198 displacement |= 0xFFFF0000;
3199 betterDstAddr = srcAddr+displacement;
3200 //fprintf(stderr, "betterDstAddr=0x%08X, srcAddr=0x%08X, displacement=0x%08X\n", betterDstAddr, srcAddr, displacement);
3201 makeReferenceWithToBase(A::kBranch14, srcAddr, betterDstAddr, dstAddr);
3202 }
3203 break;
3204 case PPC_RELOC_BR24:
3205 {
3206 instruction = BigEndian::get32(*fixUpPtr);
3207 if ( (instruction & 0x4C000000) == 0x48000000 ) {
3208 displacement = (instruction & 0x03FFFFFC);
3209 if ( (displacement & 0x02000000) != 0 )
3210 displacement |= 0xFC000000;
3211 betterDstAddr = srcAddr+displacement;
3212 makeReferenceWithToBase(A::kBranch24, srcAddr, betterDstAddr, dstAddr);
3213 }
3214 }
3215 break;
3216 case PPC_RELOC_LO16_SECTDIFF:
3217 {
3218 if ( ! nextRelocIsPair ) {
3219 warning("PPC_RELOC_LO16_SECTDIFF missing following PAIR");
3220 break;
3221 }
3222 instruction = BigEndian::get32(*fixUpPtr);
3223 lowBits = (instruction & 0xFFFF);
3224 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
3225 makeReferenceWithToBase(A::kPICBaseLow16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
3226 }
3227 break;
3228 case PPC_RELOC_LO14_SECTDIFF:
3229 {
3230 if ( ! nextRelocIsPair ) {
3231 warning("PPC_RELOC_LO14_SECTDIFF missing following PAIR");
3232 break;
3233 }
3234 instruction = BigEndian::get32(*fixUpPtr);
3235 lowBits = (instruction & 0xFFFC);
3236 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
3237 makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
3238 }
3239 break;
3240 case PPC_RELOC_HA16_SECTDIFF:
3241 {
3242 if ( ! nextRelocIsPair ) {
3243 warning("PPC_RELOC_HA16_SECTDIFF missing following PAIR");
3244 break;
3245 }
3246 instruction = BigEndian::get32(*fixUpPtr);
3247 lowBits = (nextRelocAddress & 0x0000FFFF);
3248 displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
3249 makeReferenceWithToBase(A::kPICBaseHigh16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
3250 }
3251 break;
3252 case PPC_RELOC_LO14:
3253 {
3254 if ( ! nextRelocIsPair ) {
3255 warning("PPC_RELOC_LO14 missing following PAIR");
3256 break;
3257 }
3258 instruction = BigEndian::get32(*fixUpPtr);
3259 lowBits = (instruction & 0xFFFC);
3260 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
3261 makeReferenceWithToBase(A::kAbsLow14, srcAddr, betterDstAddr, dstAddr);
3262 }
3263 break;
3264 case PPC_RELOC_LO16:
3265 {
3266 if ( ! nextRelocIsPair ) {
3267 warning("PPC_RELOC_LO16 missing following PAIR");
3268 break;
3269 }
3270 instruction = BigEndian::get32(*fixUpPtr);
3271 lowBits = (instruction & 0xFFFF);
3272 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
3273 makeReferenceWithToBase(A::kAbsLow16, srcAddr, betterDstAddr, dstAddr);
3274 }
3275 break;
3276 case PPC_RELOC_HA16:
3277 {
3278 if ( ! nextRelocIsPair ) {
3279 warning("PPC_RELOC_HA16 missing following PAIR");
3280 break;
3281 }
3282 instruction = BigEndian::get32(*fixUpPtr);
3283 lowBits = (nextRelocAddress & 0xFFFF);
3284 betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
3285 makeReferenceWithToBase(A::kAbsHigh16AddLow, srcAddr, betterDstAddr, dstAddr);
3286 }
3287 break;
3288 case PPC_RELOC_HI16:
3289 {
3290 if ( ! nextRelocIsPair ) {
3291 warning("PPC_RELOC_HI16 missing following PAIR");
3292 break;
3293 }
3294 instruction = BigEndian::get32(*fixUpPtr);
3295 lowBits = (nextRelocAddress & 0xFFFF);
3296 betterDstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF);
3297 makeReferenceWithToBase(A::kAbsHigh16, srcAddr, betterDstAddr, dstAddr);
3298 }
3299 break;
3300 case PPC_RELOC_SECTDIFF:
3301 case PPC_RELOC_LOCAL_SECTDIFF:
3302 {
3303 if ( ! nextRelocIsPair ) {
3304 warning("PPC_RELOC_SECTDIFF missing following pair");
3305 break;
3306 }
3307 Kinds kind = A::kPointerDiff32;;
3308 uint32_t contentAddr = 0;
3309 switch ( sreloc->r_length() ) {
3310 case 0:
3311 throw "bad diff relocations r_length (0) for ppc architecture";
3312 case 1:
3313 kind = A::kPointerDiff16;
3314 contentAddr = BigEndian::get16(*((uint16_t*)fixUpPtr));
3315 break;
3316 case 2:
3317 kind = A::kPointerDiff32;
3318 contentAddr = BigEndian::get32(*fixUpPtr);
3319 break;
3320 case 3:
3321 kind = A::kPointerDiff64;
3322 contentAddr = BigEndian::get64(*((uint64_t*)fixUpPtr));
3323 break;
3324 }
3325 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
3326 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
3327 AtomAndOffset toao = findAtomAndOffset(dstAddr);
3328 // check for addend encoded in the section content
3329 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
3330 // dstAddr, nextRelocValue, contentAddr);
3331 if ( (dstAddr - nextRelocValue) != contentAddr ) {
3332 if ( toao.atom == srcao.atom )
3333 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
3334 else if ( fromao.atom == srcao.atom )
3335 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
3336 else
3337 fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
3338 }
3339 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
3340 // srcao.atom->getDisplayName(), srcao.offset,
3341 // fromao.atom->getDisplayName(), fromao.offset,
3342 // toao.atom->getDisplayName(), toao.offset);
3343 new Reference<A>(kind, srcao, fromao, toao);
3344 }
3345 break;
3346 case PPC_RELOC_PAIR:
3347 break;
3348 case PPC_RELOC_HI16_SECTDIFF:
3349 warning("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF");
3350 break;
3351 default:
3352 warning("unknown scattered relocation type %d", sreloc->r_type());
3353 }
3354 }
3355 return result;
3356 }
3357
3358
3359 template <>
3360 bool Reader<x86>::addRelocReference(const macho_section<x86::P>* sect, const macho_relocation_info<x86::P>* reloc)
3361 {
3362 uint32_t srcAddr;
3363 uint32_t dstAddr;
3364 uint32_t* fixUpPtr;
3365 bool result = false;
3366 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
3367 srcAddr = sect->addr() + reloc->r_address();
3368 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
3369 switch ( reloc->r_type() ) {
3370 case GENERIC_RELOC_VANILLA:
3371 {
3372 x86::ReferenceKinds kind = x86::kPointer;
3373 uint32_t pointerValue = E::get32(*fixUpPtr);
3374 if ( reloc->r_pcrel() ) {
3375 switch( reloc->r_length() ) {
3376 case 0:
3377 kind = x86::kPCRel8;
3378 pointerValue = srcAddr + *((int8_t*)fixUpPtr) + sizeof(int8_t);
3379 break;
3380 case 1:
3381 kind = x86::kPCRel16;
3382 pointerValue = srcAddr + (int16_t)E::get16(*((uint16_t*)fixUpPtr)) + sizeof(uint16_t);
3383 break;
3384 case 2:
3385 kind = x86::kPCRel32;
3386 pointerValue += srcAddr + sizeof(uint32_t);
3387 break;
3388 case 3:
3389 throw "bad pc-rel vanilla relocation length";
3390 }
3391 }
3392 else if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
3393 kind = x86::kAbsolute32;
3394 if ( reloc->r_length() != 2 )
3395 throw "bad vanilla relocation length";
3396 }
3397 else {
3398 kind = x86::kPointer;
3399 if ( reloc->r_length() != 2 )
3400 throw "bad vanilla relocation length";
3401 }
3402 if ( reloc->r_extern() ) {
3403 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
3404 if ( this->isWeakImportSymbol(targetSymbol) ) {
3405 if ( reloc->r_pcrel() )
3406 kind = x86::kPCRel32WeakImport;
3407 else
3408 kind = x86::kPointerWeakImport;
3409 }
3410 const char* targetName = &fStrings[targetSymbol->n_strx()];
3411 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
3412 makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
3413 addDtraceExtraInfos(srcAddr, &targetName[16]);
3414 }
3415 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
3416 makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3417 addDtraceExtraInfos(srcAddr, &targetName[20]);
3418 }
3419 else
3420 makeByNameReference(kind, srcAddr, targetName, pointerValue);
3421 }
3422 else {
3423 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
3424 ObjectFile::Atom* atom = findAtomAndOffset(pointerValue).atom;
3425 const char* targetName = atom->getName();
3426 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
3427 makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
3428 addDtraceExtraInfos(srcAddr, &targetName[16]);
3429 }
3430 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
3431 makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3432 addDtraceExtraInfos(srcAddr, &targetName[20]);
3433 }
3434 else if ( reloc->r_pcrel() && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
3435 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
3436 makeReference(x86::kPCRel32WeakImport, srcAddr, pointerValue);
3437 else if ( reloc->r_symbolnum() != R_ABS )
3438 makeReference(kind, srcAddr, pointerValue);
3439 else {
3440 // find absolute symbol that corresponds to pointerValue
3441 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(pointerValue);
3442 if ( pos != fAddrToAbsoluteAtom.end() )
3443 makeByNameReference(kind, srcAddr, pos->second->getName(), 0);
3444 else
3445 throwf("R_ABS reloc but no absolute symbol at target address");
3446 }
3447 }
3448 }
3449 break;
3450 default:
3451 warning("unknown relocation type %d", reloc->r_type());
3452 }
3453 }
3454 else {
3455 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
3456 srcAddr = sect->addr() + sreloc->r_address();
3457 dstAddr = sreloc->r_value();
3458 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
3459 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
3460 const macho_relocation_info<P>* nextReloc = &reloc[1];
3461 pint_t betterDstAddr;
3462 // file format allows pair to be scattered or not
3463 bool nextRelocIsPair = false;
3464 uint32_t nextRelocAddress = 0;
3465 uint32_t nextRelocValue = 0;
3466 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
3467 if ( nextReloc->r_type() == GENERIC_RELOC_PAIR ) {
3468 nextRelocIsPair = true;
3469 nextRelocAddress = nextReloc->r_address();
3470 result = true;
3471 }
3472 }
3473 else {
3474 if ( nextSReloc->r_type() == GENERIC_RELOC_PAIR ) {
3475 nextRelocIsPair = true;
3476 nextRelocAddress = nextSReloc->r_address();
3477 nextRelocValue = nextSReloc->r_value();
3478 }
3479 }
3480 switch (sreloc->r_type()) {
3481 case GENERIC_RELOC_VANILLA:
3482 betterDstAddr = LittleEndian::get32(*fixUpPtr);
3483 //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr);
3484 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
3485 if ( sreloc->r_pcrel() ) {
3486 betterDstAddr += srcAddr + 4;
3487 makeReferenceWithToBase(x86::kPCRel32, srcAddr, betterDstAddr, dstAddr);
3488 }
3489 else {
3490 if ( strcmp(sect->segname(), "__TEXT") == 0 )
3491 makeReferenceWithToBase(x86::kAbsolute32, srcAddr, betterDstAddr, dstAddr);
3492 else
3493 makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
3494 }
3495 break;
3496 case GENERIC_RELOC_SECTDIFF:
3497 case GENERIC_RELOC_LOCAL_SECTDIFF:
3498 {
3499 if ( !nextRelocIsPair ) {
3500 warning("GENERIC_RELOC_SECTDIFF missing following pair");
3501 break;
3502 }
3503 x86::ReferenceKinds kind = x86::kPointerDiff;
3504 uint32_t contentAddr = 0;
3505 switch ( sreloc->r_length() ) {
3506 case 0:
3507 case 3:
3508 throw "bad length for GENERIC_RELOC_SECTDIFF";
3509 case 1:
3510 kind = x86::kPointerDiff16;
3511 contentAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr));
3512 break;
3513 case 2:
3514 kind = x86::kPointerDiff;
3515 contentAddr = LittleEndian::get32(*fixUpPtr);
3516 break;
3517 }
3518 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
3519 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
3520 AtomAndOffset toao = findAtomAndOffset(dstAddr);
3521 // check for addend encoded in the section content
3522 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
3523 // dstAddr, nextRelocValue, contentAddr);
3524 if ( (dstAddr - nextRelocValue) != contentAddr ) {
3525 if ( toao.atom == srcao.atom )
3526 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
3527 else if ( fromao.atom == srcao.atom )
3528 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
3529 else
3530 fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
3531 }
3532 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
3533 // srcao.atom->getDisplayName(), srcao.offset,
3534 // fromao.atom->getDisplayName(), fromao.offset,
3535 // toao.atom->getDisplayName(), toao.offset);
3536 new Reference<x86>(kind, srcao, fromao, toao);
3537 }
3538 break;
3539 case GENERIC_RELOC_PAIR:
3540 // do nothing, already used via a look ahead
3541 break;
3542 default:
3543 warning("unknown scattered relocation type %d", sreloc->r_type());
3544 }
3545 }
3546 return result;
3547 }
3548
3549 template <>
3550 bool Reader<x86_64>::addRelocReference(const macho_section<x86_64::P>* sect, const macho_relocation_info<x86_64::P>* reloc)
3551 {
3552 uint64_t srcAddr;
3553 uint64_t dstAddr = 0;
3554 uint64_t addend;
3555 uint32_t* fixUpPtr;
3556 x86_64::ReferenceKinds kind = x86_64::kNoFixUp;
3557 bool result = false;
3558 const macho_nlist<P>* targetSymbol = NULL;
3559 const char* targetName = NULL;
3560 srcAddr = sect->addr() + reloc->r_address();
3561 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
3562 //fprintf(stderr, "addReloc type=%d\n", reloc->r_type());
3563 if ( reloc->r_extern() ) {
3564 targetSymbol = &fSymbols[reloc->r_symbolnum()];
3565 targetName = &fStrings[targetSymbol->n_strx()];
3566 }
3567 switch ( reloc->r_type() ) {
3568 case X86_64_RELOC_UNSIGNED:
3569 if ( reloc->r_pcrel() )
3570 throw "pcrel and X86_64_RELOC_UNSIGNED not supported";
3571 if ( reloc->r_length() != 3 )
3572 throw "length < 3 and X86_64_RELOC_UNSIGNED not supported";
3573 dstAddr = E::get64(*((uint64_t*)fixUpPtr));
3574 if ( reloc->r_extern() ) {
3575 makeReferenceToSymbol(x86_64::kPointer, srcAddr, targetSymbol, dstAddr);
3576 }
3577 else {
3578 makeReference(x86_64::kPointer, srcAddr, dstAddr);
3579 // verify that dstAddr is in the section being targeted
3580 int sectNum = reloc->r_symbolnum();
3581 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
3582 const macho_section<P>* const targetSection = &sectionsStart[sectNum-1];
3583 if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
3584 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
3585 srcAddr, sect->sectname(), targetSection->sectname());
3586 }
3587 }
3588 break;
3589 case X86_64_RELOC_SIGNED:
3590 case X86_64_RELOC_SIGNED_1:
3591 case X86_64_RELOC_SIGNED_2:
3592 case X86_64_RELOC_SIGNED_4:
3593 if ( ! reloc->r_pcrel() )
3594 throw "not pcrel and X86_64_RELOC_SIGNED* not supported";
3595 if ( reloc->r_length() != 2 )
3596 throw "length != 2 and X86_64_RELOC_SIGNED* not supported";
3597 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
3598 if ( reloc->r_extern() ) {
3599 switch ( reloc->r_type() ) {
3600 case X86_64_RELOC_SIGNED:
3601 kind = x86_64::kPCRel32;
3602 // begin support for old .o files before X86_64_RELOC_SIGNED_1 was created
3603 if ( addend == (uint64_t)(-1) ) {
3604 addend = 0;
3605 kind = x86_64::kPCRel32_1;
3606 }
3607 else if ( addend == (uint64_t)(-2) ) {
3608 addend = 0;
3609 kind = x86_64::kPCRel32_2;
3610 }
3611 else if ( addend == (uint64_t)(-4) ) {
3612 addend = 0;
3613 kind = x86_64::kPCRel32_4;
3614 }
3615 break;
3616 // end support for old .o files before X86_64_RELOC_SIGNED_1 was created
3617 case X86_64_RELOC_SIGNED_1:
3618 kind = x86_64::kPCRel32_1;
3619 addend += 1;
3620 break;
3621 case X86_64_RELOC_SIGNED_2:
3622 kind = x86_64::kPCRel32_2;
3623 addend += 2;
3624 break;
3625 case X86_64_RELOC_SIGNED_4:
3626 kind = x86_64::kPCRel32_4;
3627 addend += 4;
3628 break;
3629 }
3630 makeReferenceToSymbol(kind, srcAddr, targetSymbol, addend);
3631 }
3632 else {
3633 uint64_t ripRelativeOffset = addend;
3634 switch ( reloc->r_type() ) {
3635 case X86_64_RELOC_SIGNED:
3636 dstAddr = srcAddr + 4 + ripRelativeOffset;
3637 kind = x86_64::kPCRel32;
3638 break;
3639 case X86_64_RELOC_SIGNED_1:
3640 dstAddr = srcAddr + 5 + ripRelativeOffset;
3641 kind = x86_64::kPCRel32_1;
3642 break;
3643 case X86_64_RELOC_SIGNED_2:
3644 dstAddr = srcAddr + 6 + ripRelativeOffset;
3645 kind = x86_64::kPCRel32_2;
3646 break;
3647 case X86_64_RELOC_SIGNED_4:
3648 dstAddr = srcAddr + 8 + ripRelativeOffset;
3649 kind = x86_64::kPCRel32_4;
3650 break;
3651 }
3652 makeReference(kind, srcAddr, dstAddr);
3653 // verify that dstAddr is in the section being targeted
3654 int sectNum = reloc->r_symbolnum();
3655 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
3656 const macho_section<P>* const targetSection = &sectionsStart[sectNum-1];
3657 if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
3658 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
3659 srcAddr, sect->sectname(), targetSection->sectname());
3660 }
3661 }
3662 break;
3663 case X86_64_RELOC_BRANCH:
3664 if ( ! reloc->r_pcrel() )
3665 throw "not pcrel and X86_64_RELOC_BRANCH not supported";
3666 if ( reloc->r_length() == 2 ) {
3667 dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
3668 if ( reloc->r_extern() ) {
3669 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
3670 makeByNameReference(x86_64::kDtraceProbeSite, srcAddr, targetName, 0);
3671 addDtraceExtraInfos(srcAddr, &targetName[16]);
3672 }
3673 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
3674 makeByNameReference(x86_64::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3675 addDtraceExtraInfos(srcAddr, &targetName[16]);
3676 }
3677 else if ( isWeakImportSymbol(targetSymbol) )
3678 makeReferenceToSymbol(x86_64::kBranchPCRel32WeakImport, srcAddr, targetSymbol, dstAddr);
3679 else
3680 makeReferenceToSymbol(x86_64::kBranchPCRel32, srcAddr, targetSymbol, dstAddr);
3681 }
3682 else {
3683 makeReference(x86_64::kBranchPCRel32, srcAddr, srcAddr+4+dstAddr);
3684 }
3685 }
3686 else if ( reloc->r_length() == 0 ) {
3687 dstAddr = *((int8_t*)fixUpPtr);
3688 if ( reloc->r_extern() ) {
3689 makeReferenceToSymbol(x86_64::kBranchPCRel8, srcAddr, targetSymbol, dstAddr);
3690 }
3691 else {
3692 makeReference(x86_64::kBranchPCRel8, srcAddr, srcAddr+1+dstAddr);
3693 }
3694 }
3695 else {
3696 throwf("length=%d and X86_64_RELOC_BRANCH not supported", reloc->r_length());;
3697 }
3698 break;
3699 case X86_64_RELOC_GOT:
3700 if ( ! reloc->r_extern() )
3701 throw "not extern and X86_64_RELOC_GOT not supported";
3702 if ( ! reloc->r_pcrel() )
3703 throw "not pcrel and X86_64_RELOC_GOT not supported";
3704 if ( reloc->r_length() != 2 )
3705 throw "length != 2 and X86_64_RELOC_GOT not supported";
3706 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
3707 if ( isWeakImportSymbol(targetSymbol) )
3708 makeReferenceToSymbol(x86_64::kPCRel32GOTWeakImport, srcAddr, targetSymbol, addend);
3709 else
3710 makeReferenceToSymbol(x86_64::kPCRel32GOT, srcAddr, targetSymbol, addend);
3711 break;
3712 case X86_64_RELOC_GOT_LOAD:
3713 if ( ! reloc->r_extern() )
3714 throw "not extern and X86_64_RELOC_GOT_LOAD not supported";
3715 if ( ! reloc->r_pcrel() )
3716 throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported";
3717 if ( reloc->r_length() != 2 )
3718 throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported";
3719 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
3720 if ( isWeakImportSymbol(targetSymbol) )
3721 makeReferenceToSymbol(x86_64::kPCRel32GOTLoadWeakImport, srcAddr, targetSymbol, addend);
3722 else
3723 makeReferenceToSymbol(x86_64::kPCRel32GOTLoad, srcAddr, targetSymbol, addend);
3724 break;
3725 case X86_64_RELOC_SUBTRACTOR:
3726 {
3727 if ( reloc->r_pcrel() )
3728 throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
3729 if ( reloc->r_length() < 2 )
3730 throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
3731 if ( !reloc->r_extern() )
3732 throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1";
3733 const macho_relocation_info<x86_64::P>* nextReloc = &reloc[1];
3734 if ( nextReloc->r_type() != X86_64_RELOC_UNSIGNED )
3735 throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED";
3736 result = true;
3737 if ( nextReloc->r_pcrel() )
3738 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
3739 if ( nextReloc->r_length() != reloc->r_length() )
3740 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length";
3741 Reference<x86_64>* ref;
3742 bool negativeAddend;
3743 if ( reloc->r_length() == 2 ) {
3744 kind = x86_64::kPointerDiff32;
3745 dstAddr = E::get32(*fixUpPtr); // addend is in content
3746 negativeAddend = ((dstAddr & 0x80000000) != 0);
3747 }
3748 else {
3749 kind = x86_64::kPointerDiff;
3750 dstAddr = E::get64(*((uint64_t*)fixUpPtr)); // addend is in content
3751 negativeAddend = ((dstAddr & 0x8000000000000000ULL) != 0);
3752 }
3753 ObjectFile::Atom* inAtom = this->findAtomAndOffset(srcAddr).atom;
3754 // create reference with "to" target
3755 if ( nextReloc->r_extern() ) {
3756 const macho_nlist<P>* targetSymbol = &fSymbols[nextReloc->r_symbolnum()];
3757 const char* targetName = &fStrings[targetSymbol->n_strx()];
3758 ref = makeReferenceToSymbol(kind, srcAddr, targetSymbol, 0);
3759 // if "to" is in this atom, change by-name to a direct reference
3760 if ( strcmp(targetName, inAtom->getName()) == 0 )
3761 ref->setTarget(*inAtom, 0);
3762 }
3763 else {
3764 ref = makeReference(kind, srcAddr, dstAddr);
3765 }
3766 // add in "from" target
3767 if ( reloc->r_extern() ) {
3768 const macho_nlist<P>* targetFromSymbol = &fSymbols[reloc->r_symbolnum()];
3769 const char* fromTargetName = &fStrings[targetFromSymbol->n_strx()];
3770 if ( (targetFromSymbol->n_type() & N_EXT) == 0 ) {
3771 // from target is translation unit scoped, so use a direct reference
3772 ref->setFromTarget(*(findAtomAndOffset(targetSymbol->n_value()).atom));
3773 }
3774 else if ( strcmp(fromTargetName, inAtom->getName()) == 0 ) {
3775 // if "from" is in this atom, change by-name to a direct reference
3776 ref->setFromTarget(*inAtom);
3777 }
3778 else {
3779 // some non-static other atom
3780 ref->setFromTargetName(fromTargetName);
3781 }
3782 }
3783 // addend goes in from side iff negative
3784 if ( negativeAddend )
3785 ref->setFromTargetOffset(-dstAddr);
3786 else
3787 ref->setToTargetOffset(dstAddr);
3788 break;
3789 }
3790 default:
3791 warning("unknown relocation type %d", reloc->r_type());
3792 }
3793 return result;
3794 }
3795
3796
3797 /// Reader<arm>::addRelocReference -
3798 /// turns arm relocation entries into references. Returns true if the next
3799 /// relocation should be skipped, false otherwise.
3800 template <>
3801 bool Reader<arm>::addRelocReference(const macho_section<arm::P>* sect,
3802 const macho_relocation_info<arm::P>* reloc)
3803 {
3804 uint32_t * fixUpPtr;
3805 int32_t displacement;
3806 uint32_t instruction = 0;
3807 bool result = false;
3808 uint32_t srcAddr;
3809 uint32_t dstAddr;
3810 uint32_t pointerValue;
3811
3812 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
3813 // non-scattered relocation
3814 const char* targetName = NULL;
3815 bool weakImport = false;
3816
3817 srcAddr = sect->addr() + reloc->r_address();
3818 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
3819 if ( reloc->r_type() != ARM_RELOC_PAIR )
3820 instruction = LittleEndian::get32(*fixUpPtr);
3821
3822 if ( reloc->r_extern() ) {
3823 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
3824 targetName = &fStrings[targetSymbol->n_strx()];
3825 weakImport = this->isWeakImportSymbol(targetSymbol);
3826 }
3827
3828 switch ( reloc->r_type() ) {
3829 case ARM_RELOC_BR24:
3830 // Sign-extend displacement
3831 displacement = (instruction & 0x00FFFFFF) << 2;
3832 if ( (displacement & 0x02000000) != 0 )
3833 displacement |= 0xFC000000;
3834 // The pc added will be +8 from the pc
3835 displacement += 8;
3836 // If this is BLX add H << 1
3837 if ((instruction & 0xFE000000) == 0xFA000000)
3838 displacement += ((instruction & 0x01000000) >> 23);
3839
3840 if ( reloc->r_extern() ) {
3841 uint32_t offsetInTarget = srcAddr + displacement;
3842 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
3843 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
3844 addDtraceExtraInfos(srcAddr, &targetName[16]);
3845 }
3846 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
3847 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3848 addDtraceExtraInfos(srcAddr, &targetName[20]);
3849 }
3850 else if ( weakImport )
3851 makeByNameReference(arm::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
3852 else
3853 makeByNameReference(arm::kBranch24, srcAddr, targetName, offsetInTarget);
3854 }
3855 else {
3856 dstAddr = srcAddr + displacement;
3857 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
3858 // check for dtrace probes and weak_import stubs
3859 const char* targetName = atom->getName();
3860 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
3861 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
3862 addDtraceExtraInfos(srcAddr, &targetName[16]);
3863 }
3864 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
3865 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3866 addDtraceExtraInfos(srcAddr, &targetName[20]);
3867 }
3868 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
3869 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
3870 makeReference(arm::kBranch24WeakImport, srcAddr, dstAddr);
3871 else if ( reloc->r_symbolnum() != R_ABS )
3872 makeReference(arm::kBranch24, srcAddr, dstAddr);
3873 else {
3874 // find absolute symbol that corresponds to pointerValue
3875 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
3876 if ( pos != fAddrToAbsoluteAtom.end() )
3877 makeByNameReference(arm::kBranch24, srcAddr, pos->second->getName(), 0);
3878 else
3879 throwf("R_ABS reloc but no absolute symbol at target address");
3880 }
3881 }
3882 break;
3883
3884 case ARM_THUMB_RELOC_BR22:
3885 // First instruction has upper 11 bits of the displacement.
3886 displacement = (instruction & 0x7FF) << 12;
3887 if ( (displacement & 0x400000) != 0 )
3888 displacement |= 0xFF800000;
3889 // Second instruction has lower eleven bits of the displacement.
3890 displacement += ((instruction >> 16) & 0x7FF) << 1;
3891 // The pc added will be +4 from the pc
3892 displacement += 4;
3893 // If the instruction was blx, force the low 2 bits to be clear
3894 dstAddr = srcAddr + displacement;
3895 if ((instruction & 0xF8000000) == 0xE8000000)
3896 dstAddr &= 0xFFFFFFFC;
3897
3898 if ( reloc->r_extern() ) {
3899 uint32_t offsetInTarget = dstAddr;
3900 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
3901 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
3902 addDtraceExtraInfos(srcAddr, &targetName[16]);
3903 }
3904 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
3905 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3906 addDtraceExtraInfos(srcAddr, &targetName[20]);
3907 }
3908 else if ( weakImport )
3909 makeByNameReference(arm::kThumbBranch22WeakImport, srcAddr, targetName, offsetInTarget);
3910 else
3911 makeByNameReference(arm::kThumbBranch22, srcAddr, targetName, offsetInTarget);
3912 }
3913 else {
3914 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
3915 // check for dtrace probes and weak_import stubs
3916 const char* targetName = atom->getName();
3917 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
3918 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
3919 addDtraceExtraInfos(srcAddr, &targetName[16]);
3920 }
3921 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
3922 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3923 addDtraceExtraInfos(srcAddr, &targetName[20]);
3924 }
3925 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
3926 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
3927 makeReference(arm::kThumbBranch22WeakImport, srcAddr, dstAddr);
3928 else if ( reloc->r_symbolnum() != R_ABS )
3929 makeReference(arm::kThumbBranch22, srcAddr, dstAddr);
3930 else {
3931 // find absolute symbol that corresponds to pointerValue
3932 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
3933 if ( pos != fAddrToAbsoluteAtom.end() )
3934 makeByNameReference(arm::kThumbBranch22, srcAddr, pos->second->getName(), 0);
3935 else
3936 throwf("R_ABS reloc but no absolute symbol at target address");
3937 }
3938 }
3939 break;
3940
3941 case ARM_RELOC_VANILLA:
3942 if ( reloc->r_length() != 2 )
3943 throw "bad length for ARM_RELOC_VANILLA";
3944
3945 pointerValue = instruction;
3946 if ( reloc->r_extern() ) {
3947 if ( weakImport )
3948 makeByNameReference(arm::kPointerWeakImport, srcAddr, targetName, pointerValue);
3949 else
3950 makeByNameReference(arm::kPointer, srcAddr, targetName, pointerValue);
3951 }
3952 else {
3953 makeReference(arm::kPointer, srcAddr, pointerValue);
3954 }
3955 break;
3956
3957 default:
3958 warning("unexpected relocation type %u", reloc->r_type());
3959 break;
3960 }
3961 }
3962 else {
3963 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
3964 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
3965 srcAddr = sect->addr() + sreloc->r_address();
3966 dstAddr = sreloc->r_value();
3967 uint32_t betterDstAddr;
3968 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
3969 instruction = LittleEndian::get32(*fixUpPtr);
3970
3971 // A ARM_RELOC_PAIR only follows ARM_RELOC_{SECTDIFF,LOCAL_SECTDIFF}
3972 // relocation types, and it is an error to see one otherwise.
3973 bool nextRelocIsPair = false;
3974 uint32_t nextRelocAddress = 0;
3975 uint32_t nextRelocValue = 0;
3976 if ( nextSReloc->r_type() == ARM_RELOC_PAIR ) {
3977 nextRelocIsPair = true;
3978 nextRelocAddress = nextSReloc->r_address();
3979 nextRelocValue = nextSReloc->r_value();
3980 result = true;
3981 }
3982
3983 switch (sreloc->r_type()) {
3984 case ARM_RELOC_VANILLA:
3985 if ( sreloc->r_length() != 2 )
3986 throw "bad length for ARM_RELOC_VANILLA";
3987
3988 betterDstAddr = LittleEndian::get32(*fixUpPtr);
3989 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
3990 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
3991 makeReferenceWithToBase(arm::kPointer, srcAddr, betterDstAddr, dstAddr);
3992 break;
3993
3994 case ARM_RELOC_BR24:
3995 // Sign-extend displacement
3996 displacement = (instruction & 0x00FFFFFF) << 2;
3997 if ( (displacement & 0x02000000) != 0 )
3998 displacement |= 0xFC000000;
3999 // The pc added will be +8 from the pc
4000 displacement += 8;
4001 // If this is BLX add H << 1
4002 if ((instruction & 0xFE000000) == 0xFA000000)
4003 displacement += ((instruction & 0x01000000) >> 23);
4004 betterDstAddr = srcAddr+displacement;
4005 makeReferenceWithToBase(arm::kBranch24, srcAddr, betterDstAddr, dstAddr);
4006 break;
4007
4008 case ARM_THUMB_RELOC_BR22:
4009 // First instruction has upper 11 bits of the displacement.
4010 displacement = (instruction & 0x7FF) << 12;
4011 if ( (displacement & 0x400000) != 0 )
4012 displacement |= 0xFF800000;
4013 // Second instruction has lower eleven bits of the displacement.
4014 displacement += ((instruction >> 16) & 0x7FF) << 1;
4015 // The pc added will be +4 from the pc
4016 displacement += 4;
4017 betterDstAddr = srcAddr+displacement;
4018 // If the instruction was blx, force the low 2 bits to be clear
4019 if ((instruction & 0xF8000000) == 0xE8000000)
4020 betterDstAddr &= 0xFFFFFFFC;
4021 makeReferenceWithToBase(arm::kThumbBranch22, srcAddr, betterDstAddr, dstAddr);
4022 break;
4023
4024 case ARM_RELOC_SECTDIFF:
4025 case ARM_RELOC_LOCAL_SECTDIFF:
4026 if ( !nextRelocIsPair ) {
4027 warning("ARM_RELOC_SECTDIFF missing following pair");
4028 break;
4029 }
4030 if ( sreloc->r_length() != 2 )
4031 throw "bad length for ARM_RELOC_SECTDIFF";
4032 {
4033 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
4034 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
4035 AtomAndOffset toao = findAtomAndOffset(dstAddr);
4036 // check for addend encoded in the section content
4037 pointerValue = LittleEndian::get32(*fixUpPtr);
4038 if ( (dstAddr - nextRelocValue) != pointerValue ) {
4039 if ( toao.atom == srcao.atom )
4040 toao.offset += (pointerValue + nextRelocValue) - dstAddr;
4041 else if ( fromao.atom == srcao.atom )
4042 toao.offset += (pointerValue + nextRelocValue) - dstAddr;
4043 else
4044 fromao.offset += (dstAddr - pointerValue) - nextRelocValue;
4045 }
4046 new Reference<arm>(arm::kPointerDiff, srcao, fromao, toao);
4047 }
4048 break;
4049
4050 default:
4051 warning("unexpected srelocation type %u", sreloc->r_type());
4052 break;
4053 }
4054 }
4055 return result;
4056 }
4057
4058 template <typename A>
4059 void Reader<A>::addReferencesForSection(const macho_section<P>* sect)
4060 {
4061 // ignore dwarf sections. If ld ever supports processing dwarf, this logic will need to change
4062 if ( (sect->flags() & S_ATTR_DEBUG) == 0 ) {
4063 switch ( sect->flags() & SECTION_TYPE ) {
4064 case S_SYMBOL_STUBS:
4065 case S_LAZY_SYMBOL_POINTERS:
4066 // we ignore compiler generated stubs, so ignore those relocs too
4067 break;
4068 default:
4069 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + sect->reloff());
4070 const uint32_t relocCount = sect->nreloc();
4071 //fprintf(stderr, "relocCount = %d in section %s\n", relocCount, sect->sectname());
4072 for (uint32_t r = 0; r < relocCount; ++r) {
4073 try {
4074 if ( addRelocReference(sect, &relocs[r]) )
4075 ++r; // skip next
4076 }
4077 catch (const char* msg) {
4078 throwf("in section %s,%s reloc %u: %s", sect->segname(), sect->sectname(), r, msg);
4079 }
4080 }
4081 }
4082 }
4083 }
4084
4085
4086 template <>
4087 const char* Reference<x86>::getDescription() const
4088 {
4089 static char temp[2048];
4090 switch( fKind ) {
4091 case x86::kNoFixUp:
4092 sprintf(temp, "reference to ");
4093 break;
4094 case x86::kFollowOn:
4095 sprintf(temp, "followed by ");
4096 break;
4097 case x86::kGroupSubordinate:
4098 sprintf(temp, "group subordinate ");
4099 break;
4100 case x86::kPointerWeakImport:
4101 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
4102 break;
4103 case x86::kPointer:
4104 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
4105 break;
4106 case x86::kPointerDiff:
4107 {
4108 // by-name references have quoted names
4109 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4110 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4111 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
4112 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4113 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4114 return temp;
4115 }
4116 break;
4117 case x86::kPointerDiff16:
4118 {
4119 // by-name references have quoted names
4120 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4121 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4122 sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
4123 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4124 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4125 return temp;
4126 }
4127 break;
4128 case x86::kPCRel32WeakImport:
4129 sprintf(temp, "offset 0x%04X, rel32 reference to weak imported ", fFixUpOffsetInSrc);
4130 break;
4131 case x86::kPCRel32:
4132 sprintf(temp, "offset 0x%04X, rel32 reference to ", fFixUpOffsetInSrc);
4133 break;
4134 case x86::kPCRel16:
4135 sprintf(temp, "offset 0x%04X, rel16 reference to ", fFixUpOffsetInSrc);
4136 break;
4137 case x86::kPCRel8:
4138 sprintf(temp, "offset 0x%04X, rel8 reference to ", fFixUpOffsetInSrc);
4139 break;
4140 case x86::kAbsolute32:
4141 sprintf(temp, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc);
4142 break;
4143 case x86::kDtraceProbe:
4144 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
4145 break;
4146 case x86::kDtraceProbeSite:
4147 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
4148 break;
4149 case x86::kDtraceIsEnabledSite:
4150 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4151 break;
4152 case x86::kDtraceTypeReference:
4153 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
4154 break;
4155 }
4156 // always quote by-name references
4157 if ( fToTargetName != NULL ) {
4158 strcat(temp, "\"");
4159 strcat(temp, fToTargetName);
4160 strcat(temp, "\"");
4161 }
4162 else if ( fToTarget.atom != NULL ) {
4163 strcat(temp, fToTarget.atom->getDisplayName());
4164 }
4165 else {
4166 strcat(temp, "NULL target");
4167 }
4168 if ( fToTarget.offset != 0 )
4169 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
4170
4171 return temp;
4172 }
4173
4174
4175 template <>
4176 const char* Reference<ppc>::getDescription() const
4177 {
4178 static char temp[2048];
4179 switch( fKind ) {
4180 case ppc::kNoFixUp:
4181 sprintf(temp, "reference to ");
4182 break;
4183 case ppc::kFollowOn:
4184 sprintf(temp, "followed by ");
4185 break;
4186 case ppc::kGroupSubordinate:
4187 sprintf(temp, "group subordinate ");
4188 break;
4189 case ppc::kPointerWeakImport:
4190 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
4191 break;
4192 case ppc::kPointer:
4193 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
4194 break;
4195 case ppc::kPointerDiff16:
4196 {
4197 // by-name references have quoted names
4198 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4199 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4200 sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
4201 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4202 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4203 return temp;
4204 }
4205 case ppc::kPointerDiff32:
4206 {
4207 // by-name references have quoted names
4208 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4209 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4210 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
4211 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4212 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4213 return temp;
4214 }
4215 case ppc::kPointerDiff64:
4216 throw "unsupported refrence kind";
4217 break;
4218 case ppc::kBranch24WeakImport:
4219 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
4220 break;
4221 case ppc::kBranch24:
4222 case ppc::kBranch14:
4223 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
4224 break;
4225 case ppc::kPICBaseLow16:
4226 sprintf(temp, "offset 0x%04X, low 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
4227 break;
4228 case ppc::kPICBaseLow14:
4229 sprintf(temp, "offset 0x%04X, low 14 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
4230 break;
4231 case ppc::kPICBaseHigh16:
4232 sprintf(temp, "offset 0x%04X, high 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
4233 break;
4234 case ppc::kAbsLow16:
4235 sprintf(temp, "offset 0x%04X, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
4236 break;
4237 case ppc::kAbsLow14:
4238 sprintf(temp, "offset 0x%04X, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
4239 break;
4240 case ppc::kAbsHigh16:
4241 sprintf(temp, "offset 0x%04X, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
4242 break;
4243 case ppc::kAbsHigh16AddLow:
4244 sprintf(temp, "offset 0x%04X, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
4245 break;
4246 case ppc::kDtraceProbe:
4247 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
4248 break;
4249 case ppc::kDtraceProbeSite:
4250 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
4251 break;
4252 case ppc::kDtraceIsEnabledSite:
4253 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4254 break;
4255 case ppc::kDtraceTypeReference:
4256 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
4257 break;
4258 }
4259 // always quote by-name references
4260 if ( fToTargetName != NULL ) {
4261 strcat(temp, "\"");
4262 strcat(temp, fToTargetName);
4263 strcat(temp, "\"");
4264 }
4265 else if ( fToTarget.atom != NULL ) {
4266 strcat(temp, fToTarget.atom->getDisplayName());
4267 }
4268 else {
4269 strcat(temp, "NULL target");
4270 }
4271 if ( fToTarget.offset != 0 )
4272 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
4273
4274 return temp;
4275 }
4276
4277 template <>
4278 const char* Reference<ppc64>::getDescription() const
4279 {
4280 static char temp[2048];
4281 switch( fKind ) {
4282 case ppc64::kNoFixUp:
4283 sprintf(temp, "reference to ");
4284 break;
4285 case ppc64::kFollowOn:
4286 sprintf(temp, "followed by ");
4287 break;
4288 case ppc64::kGroupSubordinate:
4289 sprintf(temp, "group subordinate ");
4290 break;
4291 case ppc64::kPointerWeakImport:
4292 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
4293 break;
4294 case ppc64::kPointer:
4295 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
4296 break;
4297 case ppc64::kPointerDiff64:
4298 {
4299 // by-name references have quoted names
4300 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4301 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4302 sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
4303 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4304 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4305 return temp;
4306 }
4307 case ppc64::kPointerDiff32:
4308 {
4309 // by-name references have quoted names
4310 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4311 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4312 sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
4313 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4314 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4315 return temp;
4316 }
4317 case ppc64::kPointerDiff16:
4318 {
4319 // by-name references have quoted names
4320 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4321 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4322 sprintf(temp, "offset 0x%04llX, 16-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
4323 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4324 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4325 return temp;
4326 }
4327 case ppc64::kBranch24WeakImport:
4328 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
4329 break;
4330 case ppc64::kBranch24:
4331 case ppc64::kBranch14:
4332 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to ", fFixUpOffsetInSrc);
4333 break;
4334 case ppc64::kPICBaseLow16:
4335 sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
4336 break;
4337 case ppc64::kPICBaseLow14:
4338 sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
4339 break;
4340 case ppc64::kPICBaseHigh16:
4341 sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
4342 break;
4343 case ppc64::kAbsLow16:
4344 sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
4345 break;
4346 case ppc64::kAbsLow14:
4347 sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
4348 break;
4349 case ppc64::kAbsHigh16:
4350 sprintf(temp, "offset 0x%04llX, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
4351 break;
4352 case ppc64::kAbsHigh16AddLow:
4353 sprintf(temp, "offset 0x%04llX, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
4354 break;
4355 case ppc64::kDtraceProbe:
4356 sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
4357 break;
4358 case ppc64::kDtraceProbeSite:
4359 sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
4360 break;
4361 case ppc64::kDtraceIsEnabledSite:
4362 sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4363 break;
4364 case ppc64::kDtraceTypeReference:
4365 sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
4366 break;
4367 }
4368 // always quote by-name references
4369 if ( fToTargetName != NULL ) {
4370 strcat(temp, "\"");
4371 strcat(temp, fToTargetName);
4372 strcat(temp, "\"");
4373 }
4374 else if ( fToTarget.atom != NULL ) {
4375 strcat(temp, fToTarget.atom->getDisplayName());
4376 }
4377 else {
4378 strcat(temp, "NULL target");
4379 }
4380 if ( fToTarget.offset != 0 )
4381 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
4382
4383 return temp;
4384 }
4385
4386
4387 template <>
4388 const char* Reference<x86_64>::getDescription() const
4389 {
4390 static char temp[2048];
4391 switch( fKind ) {
4392 case x86_64::kNoFixUp:
4393 sprintf(temp, "reference to ");
4394 break;
4395 case x86_64::kFollowOn:
4396 sprintf(temp, "followed by ");
4397 break;
4398 case x86_64::kGroupSubordinate:
4399 sprintf(temp, "group subordinate ");
4400 break;
4401 case x86_64::kPointerWeakImport:
4402 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
4403 break;
4404 case x86_64::kPointer:
4405 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
4406 break;
4407 case x86_64::kPointerDiff32:
4408 case x86_64::kPointerDiff:
4409 {
4410 // by-name references have quoted names
4411 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4412 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4413 const char* size = (fKind == x86_64::kPointerDiff32) ? "32-bit" : "64-bit";
4414 sprintf(temp, "offset 0x%04llX, %s pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
4415 fFixUpOffsetInSrc, size, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4416 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4417 return temp;
4418 }
4419 break;
4420 case x86_64::kPCRel32:
4421 sprintf(temp, "offset 0x%04llX, rel32 reference to ", fFixUpOffsetInSrc);
4422 break;
4423 case x86_64::kPCRel32_1:
4424 sprintf(temp, "offset 0x%04llX, rel32-1 reference to ", fFixUpOffsetInSrc);
4425 break;
4426 case x86_64::kPCRel32_2:
4427 sprintf(temp, "offset 0x%04llX, rel32-2 reference to ", fFixUpOffsetInSrc);
4428 break;
4429 case x86_64::kPCRel32_4:
4430 sprintf(temp, "offset 0x%04llX, rel32-4 reference to ", fFixUpOffsetInSrc);
4431 break;
4432 case x86_64::kBranchPCRel32:
4433 sprintf(temp, "offset 0x%04llX, branch rel32 reference to ", fFixUpOffsetInSrc);
4434 break;
4435 case x86_64::kBranchPCRel32WeakImport:
4436 sprintf(temp, "offset 0x%04llX, branch rel32 reference to weak imported ", fFixUpOffsetInSrc);
4437 break;
4438 case x86_64::kPCRel32GOT:
4439 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
4440 break;
4441 case x86_64::kPCRel32GOTWeakImport:
4442 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
4443 break;
4444 case x86_64::kPCRel32GOTLoad:
4445 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
4446 break;
4447 case x86_64::kPCRel32GOTLoadWeakImport:
4448 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
4449 break;
4450 case x86_64::kBranchPCRel8:
4451 sprintf(temp, "offset 0x%04llX, branch rel8 reference to ", fFixUpOffsetInSrc);
4452 break;
4453 case x86_64::kDtraceProbe:
4454 sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
4455 break;
4456 case x86_64::kDtraceProbeSite:
4457 sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
4458 break;
4459 case x86_64::kDtraceIsEnabledSite:
4460 sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4461 break;
4462 case x86_64::kDtraceTypeReference:
4463 sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
4464 break;
4465 }
4466 // always quote by-name references
4467 if ( fToTargetName != NULL ) {
4468 strcat(temp, "\"");
4469 strcat(temp, fToTargetName);
4470 strcat(temp, "\"");
4471 }
4472 else if ( fToTarget.atom != NULL ) {
4473 strcat(temp, fToTarget.atom->getDisplayName());
4474 }
4475 else {
4476 strcat(temp, "NULL target");
4477 }
4478 if ( fToTarget.offset != 0 )
4479 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
4480
4481 return temp;
4482 }
4483
4484 template <>
4485 const char* Reference<arm>::getDescription() const
4486 {
4487 static char temp[2048];
4488 switch( fKind ) {
4489 case arm::kNoFixUp:
4490 sprintf(temp, "reference to ");
4491 break;
4492 case arm::kFollowOn:
4493 sprintf(temp, "followed by ");
4494 break;
4495 case arm::kGroupSubordinate:
4496 sprintf(temp, "group subordinate ");
4497 break;
4498 case arm::kPointer:
4499 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
4500 break;
4501 case arm::kPointerWeakImport:
4502 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
4503 break;
4504 case arm::kPointerDiff:
4505 {
4506 // by-name references have quoted names
4507 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4508 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4509 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
4510 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4511 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4512 return temp;
4513 }
4514 case arm::kBranch24:
4515 case arm::kThumbBranch22:
4516 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
4517 break;
4518 case arm::kBranch24WeakImport:
4519 case arm::kThumbBranch22WeakImport:
4520 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
4521 break;
4522 case arm::kDtraceProbe:
4523 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
4524 break;
4525 case arm::kDtraceProbeSite:
4526 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
4527 break;
4528 case arm::kDtraceIsEnabledSite:
4529 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4530 break;
4531 case arm::kDtraceTypeReference:
4532 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
4533 break;
4534 }
4535 // always quote by-name references
4536 if ( fToTargetName != NULL ) {
4537 strcat(temp, "\"");
4538 strcat(temp, fToTargetName);
4539 strcat(temp, "\"");
4540 }
4541 else if ( fToTarget.atom != NULL ) {
4542 strcat(temp, fToTarget.atom->getDisplayName());
4543 }
4544 else {
4545 strcat(temp, "NULL target");
4546 }
4547 if ( fToTarget.offset != 0 )
4548 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
4549
4550 return temp;
4551 }
4552
4553 }; // namespace relocatable
4554 }; // namespace mach_o
4555
4556 #endif // __OBJECT_FILE_MACH_O__