]> git.saurik.com Git - apple/ld64.git/blame - src/MachOReaderRelocatable.hpp
ld64-77.1.tar.gz
[apple/ld64.git] / src / MachOReaderRelocatable.hpp
CommitLineData
d696c285
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
a61fdf0a 3 * Copyright (c) 2005-2007 Apple Inc. All rights reserved.
d696c285
A
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>
69a49097 34#include <mach-o/x86_64/reloc.h>
d696c285
A
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
62extern __attribute__((noreturn)) void throwf(const char* format, ...);
63
64namespace mach_o {
65namespace relocatable {
66
67
68
74cfe461
A
69class ReferenceSorter
70{
71public:
72 bool operator()(const ObjectFile::Reference* left, const ObjectFile::Reference* right)
73 {
74 return ( left->getFixUpOffset() < right->getFixUpOffset() );
75 }
76};
77
78
d696c285
A
79// forward reference
80template <typename A> class Reader;
d696c285
A
81
82struct 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
91template <typename A>
92class Reference : public ObjectFile::Reference
93{
94public:
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
a61fdf0a
A
106 virtual ObjectFile::Reference::TargetBinding getTargetBinding() const;
107 virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const;
d696c285
A
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; }
69a49097 112 virtual uint64_t getTargetOffset() const { return (int64_t)((int32_t)fToTarget.offset); }
d696c285
A
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 = &target; fToTarget.offset = offset; }
116 virtual void setToTargetOffset(uint64_t offset) { fToTarget.offset = offset; }
117 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget.atom = &target; }
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
a61fdf0a 123 static bool fgForFinalLinkedImage;
d696c285
A
124
125private:
126 pint_t fFixUpOffsetInSrc;
127 AtomAndOffset fToTarget;
128 AtomAndOffset fFromTarget;
129 const char* fToTargetName;
130 const char* fFromTargetName;
131 Kinds fKind;
a61fdf0a 132
d696c285
A
133};
134
a61fdf0a 135template <typename A> bool Reference<A>::fgForFinalLinkedImage = true;
d696c285
A
136
137template <typename A>
138Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget)
139 : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fToTargetName(NULL), fFromTargetName(NULL),
140 fKind(kind)
141{
69a49097
A
142 // make reference a by-name unless:
143 // - the reference type is only used with direct references
144 // - the target is translation unit scoped
a61fdf0a 145 // - the target kind is not regular (is weak or tentative)
69a49097 146 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn)
a61fdf0a
A
147 && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
148 && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition) ) {
69a49097 149 fToTargetName = toTarget.atom->getName();
a61fdf0a 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());
d696c285
A
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
157template <typename A>
158Reference<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)
a61fdf0a 165 && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
d696c285
A
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
175template <typename A>
176Reference<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
a61fdf0a
A
184template <typename A>
185ObjectFile::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
199template <typename A>
200ObjectFile::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
d696c285
A
217
218template <typename A>
219class Segment : public ObjectFile::Segment
220{
221public:
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; }
227private:
228 const macho_section<typename A::P>* fSection;
229 bool fWritable;
230 bool fExecutable;
231};
232
233template <typename A>
234Segment<A>::Segment(const macho_section<typename A::P>* sect)
69a49097 235 : fSection(sect), fWritable(true), fExecutable(false)
d696c285 236{
69a49097
A
237 if ( strcmp(fSection->segname(), "__TEXT") == 0 ) {
238 fWritable = false;
d696c285
A
239 fExecutable = true;
240 }
241 else if ( strcmp(fSection->segname(), "__IMPORT") == 0 ) {
242 fWritable = true;
243 fExecutable = true;
244 }
245}
246
247
248class DataSegment : public ObjectFile::Segment
249{
250public:
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
259DataSegment DataSegment::fgSingleton;
260
a61fdf0a
A
261class LinkEditSegment : public ObjectFile::Segment
262{
263public:
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
272LinkEditSegment LinkEditSegment::fgSingleton;
d696c285
A
273
274class BaseAtom : public ObjectFile::Atom
275{
276public:
277 BaseAtom() : fStabsStartIndex(0), fStabsCount(0) {}
278
279 virtual void setSize(uint64_t size) = 0;
280 virtual void addReference(ObjectFile::Reference* ref) = 0;
74cfe461 281 virtual void sortReferences() = 0;
d696c285 282 virtual void addLineInfo(const ObjectFile::LineInfo& info) = 0;
a61fdf0a
A
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; }
d696c285
A
288
289 uint32_t fStabsStartIndex;
290 uint32_t fStabsCount;
a61fdf0a
A
291 uint32_t fOrdinal;
292};
293
294class BaseAtomSorter
295{
296public:
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 }
d696c285
A
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//
361template <typename A>
362class SymbolAtom : public BaseAtom
363{
364public:
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; }
69a49097 373 virtual SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
a61fdf0a 374 virtual bool dontDeadStrip() const;
d696c285
A
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; }
d696c285
A
381 virtual ObjectFile::Atom& getFollowOnAtom() const;
382 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return (std::vector<ObjectFile::LineInfo>*)&fLineInfo; }
74cfe461 383 virtual ObjectFile::Alignment getAlignment() const { return fAlignment; }
d696c285
A
384 virtual void copyRawContent(uint8_t buffer[]) const;
385 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
a61fdf0a 386 virtual void setSize(uint64_t size);
74cfe461
A
387 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
388 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
d696c285 389 virtual void addLineInfo(const ObjectFile::LineInfo& info) { fLineInfo.push_back(info); }
a61fdf0a
A
390 virtual uint64_t getObjectAddress() const { return fAddress; }
391 virtual const void* getSectionRecord() const { return (const void*)fSection; }
d696c285
A
392
393protected:
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>;
d696c285
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;
69a49097 415 SymbolTableInclusion fSymbolTableInclusion;
74cfe461 416 ObjectFile::Alignment fAlignment;
d696c285
A
417};
418
419
420template <typename A>
421SymbolAtom<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();
69a49097 435 }
d696c285
A
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;
69a49097
A
474 case S_16BYTE_LITERALS:
475 setSize(16);
476 break;
d696c285
A
477 case S_CSTRING_LITERALS:
478 setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1);
69a49097 479 break;
d696c285
A
480 case S_REGULAR:
481 case S_ZEROFILL:
482 case S_COALESCED:
483 // size calculate later after next atom is found
484 break;
485 }
69a49097
A
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 }
a61fdf0a
A
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 }
69a49097
A
512 else {
513 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
514 }
74cfe461
A
515 // compute alignment
516 fAlignment = ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
a61fdf0a
A
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
524template <typename A>
525bool 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 );
d696c285
A
532}
533
534
535template <typename A>
536const char* SymbolAtom<A>::getSectionName() const
537{
a61fdf0a
A
538 if ( fOwner.fOptions.fForFinalLinkedImage && (strcmp(fSection->sectname(), "__textcoal_nt") == 0) )
539 return "__text";
540
d696c285
A
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
d696c285
A
550template <typename A>
551ObjectFile::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
a61fdf0a
A
562class Beyond
563{
564public:
565 Beyond(uint64_t offset) : fOffset(offset) {}
566 bool operator()(ObjectFile::Reference* ref) const {
567 return ( ref->getFixUpOffset() >= fOffset );
568 }
569private:
570 uint64_t fOffset;
571};
572
d696c285 573
a61fdf0a
A
574template <typename A>
575void 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}
d696c285
A
583
584template <typename A>
585void 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
a61fdf0a
A
596//
597// A SymbolAliasAtom represents an alternate name for a SymbolAtom
598//
599//
d696c285 600template <typename A>
a61fdf0a 601class SymbolAliasAtom : public BaseAtom
d696c285
A
602{
603public:
a61fdf0a
A
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
632protected:
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;
d696c285
A
647};
648
649
a61fdf0a
A
650template <typename A>
651SymbolAliasAtom<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
d696c285
A
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//
680template <typename A>
681class TentativeAtom : public BaseAtom
682{
683public:
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; }
69a49097 694 virtual bool dontDeadStrip() const { return ((fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); }
d696c285
A
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; }
a61fdf0a 698 virtual const char* getSectionName() const;
d696c285 699 virtual ObjectFile::Segment& getSegment() const { return DataSegment::fgSingleton; }
d696c285
A
700 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
701 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
74cfe461 702 virtual ObjectFile::Alignment getAlignment() const;
d696c285
A
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) { }
a61fdf0a 706 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
74cfe461 707 virtual void sortReferences() { }
a61fdf0a
A
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; }
d696c285
A
711
712protected:
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
728template <typename A>
729std::vector<ObjectFile::Reference*> TentativeAtom<A>::fgNoReferences;
730
731template <typename A>
732TentativeAtom<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
752template <typename A>
74cfe461 753ObjectFile::Alignment TentativeAtom<A>::getAlignment() const
d696c285 754{
a61fdf0a
A
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 }
d696c285 766 // limit alignment of extremely large commons to 2^15 bytes (8-page)
a61fdf0a 767 if ( alignment < 12 )
74cfe461 768 return ObjectFile::Alignment(alignment);
d696c285 769 else
a61fdf0a
A
770 return ObjectFile::Alignment(12);
771}
772
773template <typename A>
774const char* TentativeAtom<A>::getSectionName() const
775{
776 if ( fOwner.fOptions.fForFinalLinkedImage || fOwner.fOptions.fMakeTentativeDefinitionsReal )
777 return "__common";
778 else
779 return "._tentdef";
d696c285
A
780}
781
a61fdf0a 782
d696c285
A
783template <typename A>
784void 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//
795template <typename A>
796class AnonymousAtom : public BaseAtom
797{
798public:
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;
69a49097
A
805 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
806 virtual bool dontDeadStrip() const { return fDontDeadStrip; }
d696c285
A
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; }
d696c285
A
813 virtual ObjectFile::Atom& getFollowOnAtom() const;
814 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
74cfe461 815 virtual ObjectFile::Alignment getAlignment() const;
d696c285 816 virtual void copyRawContent(uint8_t buffer[]) const;
69a49097 817 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
d696c285 818 virtual void setSize(uint64_t size) { fSize = size; }
74cfe461
A
819 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
820 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
a61fdf0a
A
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; }
d696c285
A
824 BaseAtom* redirectTo() { return fRedirect; }
825 bool isWeakImportStub() { return fWeakImportStub; }
a61fdf0a
A
826 void resolveName();
827
d696c285
A
828protected:
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() {}
a61fdf0a 840 static bool cstringsHaveLabels();
d696c285
A
841
842 Reader<A>& fOwner;
843 const char* fSynthesizedName;
a61fdf0a 844 const char* fDisplayName;
d696c285
A
845 const macho_section<P>* fSection;
846 uint32_t fAddress;
847 uint32_t fSize;
848 Segment<A>* fSegment;
849 ReferenceVector fReferences;
850 BaseAtom* fRedirect;
69a49097 851 bool fDontDeadStrip;
d696c285 852 bool fWeakImportStub;
69a49097
A
853 ObjectFile::Atom::SymbolTableInclusion fSymbolTableInclusion;
854 ObjectFile::Atom::Scope fScope;
d696c285
A
855};
856
857template <typename A>
858AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* section, uint32_t addr, uint32_t size)
a61fdf0a
A
859 : fOwner(owner), fSynthesizedName(NULL), fDisplayName(NULL), fSection(section), fAddress(addr), fSize(size),
860 fSegment(NULL), fDontDeadStrip(true), fWeakImportStub(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn),
69a49097 861 fScope(ObjectFile::Atom::scopeTranslationUnit)
d696c285
A
862{
863 fSegment = new Segment<A>(fSection);
864 fRedirect = this;
865 uint8_t type = fSection->flags() & SECTION_TYPE;
a61fdf0a 866 //fprintf(stderr, "AnonymousAtom(%p) addr=0x%X in %s from %s\n", this, addr, section->sectname(), owner.getPath());
d696c285
A
867 switch ( type ) {
868 case S_ZEROFILL:
869 {
870 asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr);
871 }
872 break;
a61fdf0a 873 case S_COALESCED:
d696c285 874 case S_REGULAR:
69a49097
A
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
a61fdf0a
A
877 fSynthesizedName = ".objc_class_name_PENDING";
878 owner.fAtomsPendingAName.push_back(this);
879 owner.fSectionsWithAtomsPendingAName.insert(fSection);
69a49097
A
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;
d696c285
A
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);
69a49097
A
896 fScope = ObjectFile::Atom::scopeLinkageUnit;
897 fDontDeadStrip = false;
a61fdf0a
A
898 if ( !fOwner.fOptions.fForFinalLinkedImage && cstringsHaveLabels() )
899 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
d696c285
A
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);
69a49097
A
906 fScope = ObjectFile::Atom::scopeLinkageUnit;
907 fDontDeadStrip = false;
d696c285
A
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);
69a49097
A
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;
d696c285
A
925 }
926 break;
927 case S_LITERAL_POINTERS:
928 {
a61fdf0a
A
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";
69a49097 933 fScope = ObjectFile::Atom::scopeLinkageUnit;
a61fdf0a
A
934 owner.fAtomsPendingAName.push_back(this);
935 owner.fSectionsWithAtomsPendingAName.insert(fSection);
d696c285
A
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
a61fdf0a 957 if ( ((sym->n_type() & N_TYPE) != N_UNDF) && ((sym->n_type() & N_EXT) == 0) ) {
d696c285 958 BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName);
a61fdf0a 959 if ( staticAtom != NULL )
d696c285
A
960 fRedirect = staticAtom;
961 }
a61fdf0a
A
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;
d696c285
A
967 }
968 break;
969 case S_LAZY_SYMBOL_POINTERS:
970 case S_NON_LAZY_SYMBOL_POINTERS:
971 {
69a49097
A
972 fDontDeadStrip = false;
973 fScope = ObjectFile::Atom::scopeLinkageUnit;
d696c285
A
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
d696c285
A
979 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
980 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset)));
69a49097 981 // All atoms not created yet, so we need to scan symbol table
a61fdf0a 982 const macho_nlist<P>* closestSym = NULL;
d696c285
A
983 const macho_nlist<P>* end = &fOwner.fSymbols[fOwner.fSymbolCount];
984 for (const macho_nlist<P>* sym = fOwner.fSymbols; sym < end; ++sym) {
69a49097 985 if ( ((sym->n_type() & N_TYPE) == N_SECT)
a61fdf0a
A
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 }
d696c285
A
1001 }
1002 }
a61fdf0a
A
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;
d696c285
A
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
a61fdf0a
A
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
69a49097
A
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 }
d696c285
A
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
a61fdf0a
A
1054// x86_64 uses L labels on cstrings to allow relocs with addends
1055template <> bool AnonymousAtom<x86_64>::cstringsHaveLabels() { return true; }
1056template <typename A> bool AnonymousAtom<A>::cstringsHaveLabels() { return false; }
1057
1058
1059template <typename A>
1060void 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
d696c285
A
1095
1096template <typename A>
1097const char* AnonymousAtom<A>::getDisplayName() const
1098{
1099 if ( fSynthesizedName != NULL )
1100 return fSynthesizedName;
1101
a61fdf0a
A
1102 if ( fDisplayName != NULL )
1103 return fDisplayName;
1104
d696c285
A
1105 if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) {
1106 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
a61fdf0a 1107 asprintf((char**)&fDisplayName, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset);
d696c285
A
1108 }
1109 else {
a61fdf0a 1110 asprintf((char**)&fDisplayName, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() );
d696c285 1111 }
a61fdf0a 1112 return fDisplayName;
d696c285
A
1113}
1114
a61fdf0a 1115
d696c285
A
1116template <typename A>
1117ObjectFile::Atom::Scope AnonymousAtom<A>::getScope() const
1118{
74cfe461 1119 return fScope;
d696c285
A
1120}
1121
1122template <typename A>
1123ObjectFile::Atom::DefinitionKind AnonymousAtom<A>::getDefinitionKind() const
1124{
d696c285
A
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:
69a49097 1130 case S_16BYTE_LITERALS:
a61fdf0a 1131 case S_SYMBOL_STUBS:
69a49097 1132 case S_LITERAL_POINTERS:
d696c285 1133 return ObjectFile::Atom::kWeakDefinition;
a61fdf0a
A
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;
d696c285
A
1139 default:
1140 return ObjectFile::Atom::kRegularDefinition;
1141 }
1142}
1143
1144template <typename A>
1145bool AnonymousAtom<A>::isZeroFill() const
1146{
1147 return ( (fSection->flags() & SECTION_TYPE) == S_ZEROFILL );
1148}
1149
1150
1151template <typename A>
1152const char* AnonymousAtom<A>::getSectionName() const
1153{
d696c285
A
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
1163template <typename A>
74cfe461 1164ObjectFile::Alignment AnonymousAtom<A>::getAlignment() const
d696c285 1165{
d696c285
A
1166 switch ( fSection->flags() & SECTION_TYPE ) {
1167 case S_4BYTE_LITERALS:
74cfe461 1168 return ObjectFile::Alignment(2);
d696c285 1169 case S_8BYTE_LITERALS:
74cfe461 1170 return ObjectFile::Alignment(3);
69a49097 1171 case S_16BYTE_LITERALS:
74cfe461 1172 return ObjectFile::Alignment(4);
d696c285 1173 case S_NON_LAZY_SYMBOL_POINTERS:
74cfe461 1174 return ObjectFile::Alignment((uint8_t)log2(sizeof(pint_t)));
a61fdf0a
A
1175 case S_CSTRING_LITERALS:
1176 if ( ! fOwner.fOptions.fForFinalLinkedImage )
1177 return ObjectFile::Alignment(fSection->align());
d696c285 1178 default:
74cfe461 1179 return ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
d696c285
A
1180 }
1181}
1182
d696c285
A
1183
1184template <typename A>
1185ObjectFile::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
1195template <typename A>
1196void 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
a61fdf0a
A
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//
1212template <typename A>
1213class AbsoluteAtom : public BaseAtom
1214{
1215public:
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
1244protected:
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
1260template <typename A>
1261std::vector<ObjectFile::Reference*> AbsoluteAtom<A>::fgNoReferences;
1262
1263template <typename A>
1264AbsoluteAtom<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
d696c285
A
1280
1281
1282template <typename A>
1283class Reader : public ObjectFile::Reader
1284{
1285public:
1286 static bool validFile(const uint8_t* fileContent);
a61fdf0a
A
1287 Reader(const uint8_t* fileContent, const char* path, time_t modTime,
1288 const ObjectFile::ReaderOptions& options, uint32_t ordinalBase);
d696c285
A
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; }
a61fdf0a
A
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; }
d696c285
A
1301
1302 bool getTranslationUnitSource(const char** dir, const char** name) const;
1303
1304private:
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>;
a61fdf0a 1313 friend class AbsoluteAtom<A>;
d696c285 1314 friend class SymbolAtom<A>;
a61fdf0a
A
1315
1316 void addReferencesForSection(const macho_section<P>* sect);
d696c285
A
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);
69a49097 1332 Reference<A>* makeReferenceToSymbol(Kinds kind, uint32_t atAddr, const macho_nlist<P>* toSymbol, uint32_t toOffset);
d696c285 1333 void validSectionType(uint8_t type);
a61fdf0a
A
1334 void addDtraceExtraInfos(uint32_t probeAddr, const char* providerName);
1335 void setCpuConstraint(uint32_t cpusubtype);
d696c285
A
1336
1337 BaseAtom* findAtomByName(const char*);
1338
1339 const char* fPath;
1340 time_t fModTime;
a61fdf0a 1341 uint32_t fOrdinalBase;
d696c285
A
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;
a61fdf0a 1349 std::vector<BaseAtom*> fAtoms;
d696c285 1350 std::map<uint32_t, BaseAtom*> fAddrToAtom;
a61fdf0a 1351 std::map<uint32_t, BaseAtom*> fAddrToAbsoluteAtom;
d696c285 1352 std::vector<class AnonymousAtom<A>*> fLocalNonLazys;
a61fdf0a
A
1353 std::vector<class AnonymousAtom<A>*> fAtomsPendingAName;
1354 std::set<const macho_section<P>*> fSectionsWithAtomsPendingAName;
1355 std::vector<const char*> fDtraceProviderInfo;
d696c285 1356 ObjectFile::Reader::DebugInfoKind fDebugInfo;
69a49097 1357 bool fHasUUID;
d696c285
A
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;
69a49097 1365 bool fAppleObjc;
a61fdf0a
A
1366 bool fHasDTraceProbes;
1367 bool fHaveIndirectSymbols;
1368 bool fReplacementClasses;
1369 ObjectFile::Reader::ObjcConstraint fObjConstraint;
1370 ObjectFile::Reader::CpuConstraint fCpuConstraint;
d696c285
A
1371};
1372
d696c285 1373template <typename A>
a61fdf0a
A
1374Reader<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),
d696c285 1376 fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL),
a61fdf0a
A
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)
d696c285
A
1381{
1382 // sanity check
1383 if ( ! validFile(fileContent) )
1384 throw "not a valid mach-o object file";
1385
a61fdf0a
A
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
d696c285
A
1392 // cache intersting pointers
1393 const macho_header<P>* header = (const macho_header<P>*)fileContent;
a61fdf0a 1394 this->setCpuConstraint(header->cpusubtype());
d696c285
A
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;
69a49097
A
1398 uint32_t undefinedStartIndex = 0;
1399 uint32_t undefinedEndIndex = 0;
d696c285
A
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();
a61fdf0a
A
1408 if ( undefinedEndIndex == 0 ) {
1409 undefinedStartIndex = 0;
1410 undefinedEndIndex = symtab->nsyms();
1411 }
d696c285
A
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());
69a49097
A
1418 undefinedStartIndex = dsymtab->iundefsym();
1419 undefinedEndIndex = undefinedStartIndex + dsymtab->nundefsym();
d696c285
A
1420 }
1421 break;
1422 case LC_UUID:
69a49097 1423 fHasUUID = true;
d696c285
A
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 = &sectionsStart[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>));
a61fdf0a
A
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
d696c285
A
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 = &sections[sym.n_sect()-1];
a61fdf0a 1449 pint_t sectionEndAddr = section->addr() + section->size();
d696c285
A
1450 bool suppress = false;
1451 // ignore atoms in debugger sections
1452 if ( (section->flags() & S_ATTR_DEBUG) == 0 ) {
a61fdf0a
A
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 }
d696c285
A
1499 }
1500 }
1501 }
1502 else if ( (type == N_UNDF) && (sym.n_value() != 0) ) {
1503 fAtoms.push_back(new TentativeAtom<A>(*this, &sym));
1504 }
a61fdf0a
A
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;
69a49097 1522 }
d696c285
A
1523 }
1524 }
1525
d696c285
A
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;
69a49097
A
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);
a61fdf0a
A
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;
69a49097 1590 }
a61fdf0a
A
1591 else {
1592 fprintf(stderr, "can't parse __OBJC/__image_info section in %s\n", fPath);
1593 }
1594 }
69a49097 1595 break;
d696c285
A
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;
a61fdf0a
A
1616 BaseAtom* mostAlignedEmptyString = NULL;
1617 uint32_t mostAlignedEmptyStringTrailingZeros = 0;
1618 std::vector<std::pair<uint32_t,BaseAtom*> > emptyStrings;
d696c285
A
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 ) {
a61fdf0a
A
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;
d696c285 1634 }
d696c285
A
1635 }
1636 else {
1637 fAtoms.push_back(newAtom);
1638 fAddrToAtom[stringAddr] = newAtom;
1639 }
1640 }
1641 }
a61fdf0a
A
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 }
d696c285
A
1651 }
1652 }
1653
a61fdf0a
A
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
d696c285
A
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();
a61fdf0a 1665 const bool setFollowOnAtom = ! this->canScatterAtoms();
d696c285
A
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:
69a49097 1686 // if there is not an atom already at the start of this section, add an anonymous one
d696c285
A
1687 uint32_t previousAtomAddr = 0;
1688 BaseAtom* previousAtom = NULL;
1689 if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) {
d696c285 1690 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr(), 0);
d696c285 1691 fAddrToAtom[sect->addr()] = newAtom;
a61fdf0a 1692 fAtoms.push_back(newAtom);
d696c285
A
1693 previousAtomAddr = sectionStartAddr;
1694 previousAtom = newAtom;
a61fdf0a 1695 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
d696c285
A
1696 }
1697 // calculate size of all atoms in this section and add follow-on references
a61fdf0a
A
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));
d696c285 1707 }
a61fdf0a
A
1708 previousAtomAddr = atomAddr;
1709 previousAtom = atom;
1710 }
d696c285
A
1711 }
1712 if ( previousAtom != NULL ) {
1713 // set last atom in section
1714 previousAtom->setSize(sectionEndAddr - previousAtomAddr);
1715 }
1716 break;
1717 }
1718 }
1719 }
1720 }
1721
a61fdf0a
A
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);
d696c285
A
1738 }
1739 }
a61fdf0a 1740 }
d696c285
A
1741 }
1742 }
1743 }
a61fdf0a
A
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 }
d696c285 1755
a61fdf0a
A
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);
69a49097
A
1760 }
1761
a61fdf0a 1762
69a49097
A
1763 // add objective-c references
1764 if ( fAppleObjc ) {
1765 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
a61fdf0a 1766 if ( (strcmp(sect->sectname(), "__cls_refs") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) {
69a49097 1767 for (uint32_t offset = 0; offset < sect->size(); offset += sizeof(pint_t)) {
a61fdf0a
A
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 }
69a49097
A
1778 }
1779 }
1780 }
1781 }
1782
d696c285
A
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 }
a61fdf0a 1790
d696c285
A
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
a61fdf0a
A
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 }
d696c285
A
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) ) {
69a49097
A
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;
a61fdf0a 1863 fprintf(stderr, "ld: warning can't parse dwarf compilation unit info in %s\n", this->getPath());
69a49097
A
1864 fDebugInfo = kDebugInfoNone;
1865 }
d696c285
A
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
a61fdf0a
A
1872 if ( (fDwarfDebugLineSect != NULL) && (fDwarfDebugLineSect->size() != 0) && (fAddrToAtom.size() != 0)
1873 && (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
d696c285
A
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;
69a49097 1885 while ( line_next (lines, &result, line_stop_pc) ) {
a61fdf0a
A
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);
74cfe461
A
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;
d696c285 1891 // for performance, see if in next pc is in current atom
69a49097
A
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)) ) {
d696c285
A
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
a61fdf0a
A
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 }
d696c285
A
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;
69a49097
A
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);
d696c285 1943 ((BaseAtom*)curAtom)->addLineInfo(info);
69a49097
A
1944 if ( result.end_of_sequence ) {
1945 curAtom = NULL;
1946 }
d696c285
A
1947 }
1948 line_free(lines);
1949 }
1950 else {
a61fdf0a 1951 fprintf(stderr, "ld: warning could not parse dwarf line number info in %s\n", this->getPath());
d696c285
A
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];
69a49097 1966 bool useStab = true;
d696c285
A
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 ) {
69a49097 1970 fDebugInfo = (fHasUUID ? kDebugInfoStabsUUID : kDebugInfoStabs);
d696c285
A
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:
a61fdf0a
A
2002 case N_RSYM:
2003 case N_PSYM:
d696c285
A
2004 // not associated with an atom, just copy
2005 stab.string = symString;
2006 break;
2007 case N_GSYM:
a61fdf0a 2008 {
d696c285
A
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 }
74cfe461
A
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 }
d696c285
A
2033 if ( stab.atom == NULL ) {
2034 fprintf(stderr, "can't find atom for N_GSYM stabs %s in %s\n", symString, path);
69a49097 2035 useStab = false;
d696c285
A
2036 }
2037 break;
a61fdf0a 2038 }
d696c285
A
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:
a61fdf0a 2077 {
d696c285
A
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;
a61fdf0a 2088 }
d696c285
A
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
69a49097
A
2142 if ( useStab )
2143 fStabs.push_back(stab);
d696c285
A
2144 }
2145 }
2146 }
2147
d696c285
A
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
a61fdf0a
A
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
2174template <>
2175void 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
2197template <typename A>
2198void Reader<A>::setCpuConstraint(uint32_t cpusubtype)
2199{
2200 // no cpu sub types for this architecture
2201}
2202
2203template <typename A>
2204void 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 }
d696c285
A
2220}
2221
a61fdf0a 2222
69a49097
A
2223template <>
2224void 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}
d696c285
A
2235
2236template <typename A>
2237void Reader<A>::validSectionType(uint8_t type)
2238{
2239}
2240
2241template <typename A>
2242bool Reader<A>::getTranslationUnitSource(const char** dir, const char** name) const
2243{
2244 if ( fDebugInfo == kDebugInfoDwarf ) {
2245 *dir = fDwarfTranslationUnitDir;
2246 *name = fDwarfTranslationUnitFile;
a61fdf0a 2247 return (fDwarfTranslationUnitFile != NULL);
d696c285
A
2248 }
2249 return false;
2250}
2251
2252template <typename A>
2253BaseAtom* 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
a61fdf0a 2263 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
d696c285
A
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
2273template <typename A>
2274Reference<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
2279template <typename A>
2280Reference<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
2285template <typename A>
2286Reference<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
2291template <typename A>
2292Reference<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
2297template <typename A>
2298Reference<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
2303template <typename A>
2304Reference<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;
69a49097 2310 return makeReference(A::kNoFixUp, funcAddr, ehAtomAddress);
d696c285
A
2311}
2312
2313
69a49097
A
2314template <>
2315Reference<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
2326template <>
2327Reference<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
a61fdf0a
A
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')) )
69a49097
A
2333 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toSymbol->n_value(), toSymbol->n_value()+toOffset));
2334 else
a61fdf0a 2335 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), symbolName, toOffset);
69a49097
A
2336}
2337
2338
2339template <>
2340Reference<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 }
a61fdf0a 2353 fprintf(stderr, "ld: warning, can't find matching function for eh symbol %s\n", ehName);
69a49097
A
2354 return NULL;
2355}
d696c285 2356
86b84c30 2357
d696c285
A
2358template <typename A>
2359AtomAndOffset 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
2375template <typename A>
2376AtomAndOffset 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). */
2394static void
2395skip_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. */
2405static uint64_t
2406read_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. */
2429template <typename A>
2430bool 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//
2515template <typename A>
2516bool 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
2643template <typename A>
2644const 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
2669template <>
2670bool 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
2682template <>
2683bool 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
2695template <>
2696bool 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
69a49097
A
2708template <>
2709bool 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}
d696c285
A
2720
2721
2722template <typename A>
2723bool 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
2728template <>
2729bool 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
2734template <>
2735bool 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//
2744template <typename A>
2745bool 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;
a61fdf0a
A
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 )
d696c285
A
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;
a61fdf0a
A
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)
d696c285
A
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);
a61fdf0a
A
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 }
d696c285
A
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);
a61fdf0a
A
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 }
d696c285
A
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);
a61fdf0a
A
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 }
d696c285
A
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;
a61fdf0a
A
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 }
d696c285
A
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:
a61fdf0a 2960 // this is from -mlong-branch codegen. We ignore the jump island and make reference to the real target
d696c285
A
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());
a61fdf0a
A
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 }
d696c285
A
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);
74cfe461 3063 makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
d696c285
A
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 }
a61fdf0a
A
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 }
d696c285
A
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
3171template <>
3172ppc::ReferenceKinds Reader<ppc>::pointerDiffKindForLength_powerpc(uint8_t r_length)
3173{
3174 if ( r_length == 2 )
3175 return ppc::kPointerDiff32;
a61fdf0a
A
3176 else if ( r_length == 1 )
3177 return ppc::kPointerDiff16;
d696c285
A
3178 else
3179 throw "bad diff relocations r_length for ppc architecture";
3180 }
3181
3182template <>
3183ppc64::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
3193template <>
3194bool 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 {
a61fdf0a 3206 x86::ReferenceKinds kind = x86::kPointer;
d696c285
A
3207 uint32_t pointerValue = E::get32(*fixUpPtr);
3208 if ( reloc->r_pcrel() ) {
a61fdf0a
A
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 }
d696c285 3222 }
69a49097
A
3223 else if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
3224 kind = x86::kAbsolute32;
a61fdf0a
A
3225 if ( reloc->r_length() != 2 )
3226 throw "bad vanilla relocation length";
69a49097 3227 }
d696c285
A
3228 else {
3229 kind = x86::kPointer;
a61fdf0a
A
3230 if ( reloc->r_length() != 2 )
3231 throw "bad vanilla relocation length";
d696c285
A
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()];
a61fdf0a
A
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);
d696c285
A
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;
a61fdf0a
A
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)
d696c285
A
3262 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
3263 makeReference(x86::kPCRel32WeakImport, srcAddr, pointerValue);
a61fdf0a 3264 else if ( reloc->r_symbolnum() != R_ABS )
d696c285 3265 makeReference(kind, srcAddr, pointerValue);
a61fdf0a
A
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 }
d696c285
A
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 {
69a49097
A
3317 if ( strcmp(sect->segname(), "__TEXT") == 0 )
3318 makeReferenceWithToBase(x86::kAbsolute32, srcAddr, betterDstAddr, dstAddr);
3319 else
3320 makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
d696c285
A
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 }
a61fdf0a
A
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);
d696c285
A
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
69a49097
A
3376template <>
3377bool 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;
74cfe461 3383 x86_64::ReferenceKinds kind = x86_64::kNoFixUp;
69a49097
A
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));
a61fdf0a 3401 if ( reloc->r_extern() ) {
69a49097 3402 makeReferenceToSymbol(x86_64::kPointer, srcAddr, targetSymbol, dstAddr);
a61fdf0a
A
3403 }
3404 else {
69a49097 3405 makeReference(x86_64::kPointer, srcAddr, dstAddr);
a61fdf0a
A
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 = &sectionsStart[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 }
69a49097
A
3415 break;
3416 case X86_64_RELOC_SIGNED:
86b84c30
A
3417 case X86_64_RELOC_SIGNED_1:
3418 case X86_64_RELOC_SIGNED_2:
3419 case X86_64_RELOC_SIGNED_4:
69a49097 3420 if ( ! reloc->r_pcrel() )
74cfe461 3421 throw "not pcrel and X86_64_RELOC_SIGNED* not supported";
69a49097 3422 if ( reloc->r_length() != 2 )
74cfe461
A
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;
86b84c30 3432 kind = x86_64::kPCRel32_1;
86b84c30 3433 }
74cfe461
A
3434 else if ( addend == (uint64_t)(-2) ) {
3435 addend = 0;
86b84c30 3436 kind = x86_64::kPCRel32_2;
86b84c30 3437 }
74cfe461
A
3438 else if ( addend == (uint64_t)(-4) ) {
3439 addend = 0;
86b84c30 3440 kind = x86_64::kPCRel32_4;
86b84c30 3441 }
74cfe461
A
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);
69a49097 3458 }
69a49097 3459 else {
74cfe461
A
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);
a61fdf0a
A
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 = &sectionsStart[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 }
74cfe461 3488 }
69a49097
A
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() ) {
a61fdf0a
A
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) )
69a49097
A
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:
a61fdf0a 3541 {
69a49097
A
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;
a61fdf0a 3604 }
69a49097
A
3605 default:
3606 fprintf(stderr, "unknown relocation type %d\n", reloc->r_type());
3607 }
3608 return result;
3609}
d696c285
A
3610
3611
a61fdf0a
A
3612template <typename A>
3613void 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
d696c285
A
3640template <>
3641const char* Reference<x86>::getDescription() const
3642{
69a49097 3643 static char temp[2048];
d696c285
A
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;
a61fdf0a
A
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;
d696c285
A
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;
a61fdf0a
A
3685 case x86::kPCRel16:
3686 sprintf(temp, "offset 0x%04X, rel16 reference to ", fFixUpOffsetInSrc);
3687 break;
69a49097
A
3688 case x86::kAbsolute32:
3689 sprintf(temp, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc);
3690 break;
a61fdf0a
A
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;
d696c285
A
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
3723template <>
3724const char* Reference<ppc>::getDescription() const
3725{
69a49097 3726 static char temp[2048];
d696c285
A
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;
a61fdf0a
A
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 }
d696c285
A
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:
a61fdf0a 3771 sprintf(temp, "offset 0x%04X, low 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
d696c285
A
3772 break;
3773 case ppc::kPICBaseLow14:
a61fdf0a 3774 sprintf(temp, "offset 0x%04X, low 14 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
d696c285
A
3775 break;
3776 case ppc::kPICBaseHigh16:
a61fdf0a 3777 sprintf(temp, "offset 0x%04X, high 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
d696c285
A
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:
a61fdf0a 3786 sprintf(temp, "offset 0x%04X, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
d696c285
A
3787 break;
3788 case ppc::kAbsHigh16AddLow:
a61fdf0a
A
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);
d696c285
A
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
3822template <>
3823const char* Reference<ppc64>::getDescription() const
3824{
69a49097 3825 static char temp[2048];
d696c285
A
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 }
a61fdf0a
A
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 }
d696c285
A
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:
a61fdf0a 3892 sprintf(temp, "offset 0x%04llX, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
d696c285
A
3893 break;
3894 case ppc64::kAbsHigh16AddLow:
a61fdf0a
A
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);
d696c285
A
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 )
69a49097 3923 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
d696c285
A
3924
3925 return temp;
3926}
3927
3928
69a49097
A
3929template <>
3930const 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;
a61fdf0a
A
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;
69a49097
A
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}
d696c285
A
4019
4020
86b84c30 4021
d696c285
A
4022}; // namespace relocatable
4023}; // namespace mach_o
4024
4025#endif // __OBJECT_FILE_MACH_O__