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