1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
3 * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
27 #include <sys/types.h>
30 #include <sys/sysctl.h>
44 #include <ext/hash_map>
45 #include <ext/hash_set>
50 #include "InputFiles.h"
51 #include "SymbolTable.h"
59 // HACK, I can't find a way to pass values in the compare classes (e.g. ContentFuncs)
60 // so use global variable to pass info.
61 static ld::IndirectBindingTable
* _s_indirectBindingTable
= NULL
;
64 SymbolTable::SymbolTable(const Options
& opts
, std::vector
<const ld::Atom
*>& ibt
)
65 : _options(opts
), _cstringTable(6151), _indirectBindingTable(ibt
), _hasExternalTentativeDefinitions(false)
67 _s_indirectBindingTable
= this;
71 size_t SymbolTable::ContentFuncs::operator()(const ld::Atom
* atom
) const
73 return atom
->contentHash(*_s_indirectBindingTable
);
76 bool SymbolTable::ContentFuncs::operator()(const ld::Atom
* left
, const ld::Atom
* right
) const
78 return (memcmp(left
->rawContentPointer(), right
->rawContentPointer(), left
->size()) == 0);
83 size_t SymbolTable::CStringHashFuncs::operator()(const ld::Atom
* atom
) const
85 return atom
->contentHash(*_s_indirectBindingTable
);
88 bool SymbolTable::CStringHashFuncs::operator()(const ld::Atom
* left
, const ld::Atom
* right
) const
90 return (strcmp((char*)left
->rawContentPointer(), (char*)right
->rawContentPointer()) == 0);
94 size_t SymbolTable::UTF16StringHashFuncs::operator()(const ld::Atom
* atom
) const
96 return atom
->contentHash(*_s_indirectBindingTable
);
99 bool SymbolTable::UTF16StringHashFuncs::operator()(const ld::Atom
* left
, const ld::Atom
* right
) const
103 const void* leftContent
= left
->rawContentPointer();
104 const void* rightContent
= right
->rawContentPointer();
105 unsigned int amount
= left
->size()-2;
106 bool result
= (memcmp(leftContent
, rightContent
, amount
) == 0);
111 size_t SymbolTable::ReferencesHashFuncs::operator()(const ld::Atom
* atom
) const
113 return atom
->contentHash(*_s_indirectBindingTable
);
116 bool SymbolTable::ReferencesHashFuncs::operator()(const ld::Atom
* left
, const ld::Atom
* right
) const
118 return left
->canCoalesceWith(*right
, *_s_indirectBindingTable
);
122 void SymbolTable::addDuplicateSymbol(const char *name
, const ld::Atom
*atom
)
124 // Look up or create the file list for name.
125 DuplicateSymbols::iterator symbolsIterator
= _duplicateSymbols
.find(name
);
126 DuplicatedSymbolAtomList
*atoms
= NULL
;
127 if (symbolsIterator
!= _duplicateSymbols
.end()) {
128 atoms
= symbolsIterator
->second
;
130 atoms
= new std::vector
<const ld::Atom
*>;
131 _duplicateSymbols
.insert(std::pair
<const char *, DuplicatedSymbolAtomList
*>(name
, atoms
));
134 // check if file is already in the list, add it if not
136 for (DuplicatedSymbolAtomList::iterator it
= atoms
->begin(); !found
&& it
!= atoms
->end(); it
++)
137 if (strcmp((*it
)->file()->path(), atom
->file()->path()) == 0)
140 atoms
->push_back(atom
);
143 void SymbolTable::checkDuplicateSymbols() const
145 bool foundDuplicate
= false;
146 for (DuplicateSymbols::const_iterator symbolIt
= _duplicateSymbols
.begin(); symbolIt
!= _duplicateSymbols
.end(); symbolIt
++) {
147 DuplicatedSymbolAtomList
*atoms
= symbolIt
->second
;
148 bool reportDuplicate
;
149 if (_options
.deadCodeStrip()) {
150 // search for a live atom
151 reportDuplicate
= false;
152 for (DuplicatedSymbolAtomList::iterator it
= atoms
->begin(); !reportDuplicate
&& it
!= atoms
->end(); it
++) {
154 reportDuplicate
= true;
157 reportDuplicate
= true;
159 if (reportDuplicate
) {
160 foundDuplicate
= true;
161 fprintf(stderr
, "duplicate symbol %s in:\n", symbolIt
->first
);
162 for (DuplicatedSymbolAtomList::iterator atomIt
= atoms
->begin(); atomIt
!= atoms
->end(); atomIt
++) {
163 fprintf(stderr
, " %s\n", (*atomIt
)->file()->path());
168 throwf("%d duplicate symbol%s", (int)_duplicateSymbols
.size(), _duplicateSymbols
.size()==1?"":"s");
171 // AtomPicker encapsulates the logic for picking which atom to use when adding an atom by name results in a collision
172 class NameCollisionResolution
{
174 NameCollisionResolution(const ld::Atom
& a
, const ld::Atom
& b
, bool ignoreDuplicates
, const Options
& options
) : _atomA(a
), _atomB(b
), _options(options
), _reportDuplicate(false), _ignoreDuplicates(ignoreDuplicates
) {
178 // Returns which atom to use
179 const ld::Atom
& chosen() { return *_chosen
; }
180 bool choseAtom(const ld::Atom
& atom
) { return _chosen
== &atom
; }
182 // Returns true if the two atoms should be reported as a duplicate symbol
183 bool reportDuplicate() { return _reportDuplicate
; }
186 const ld::Atom
& _atomA
;
187 const ld::Atom
& _atomB
;
188 const Options
& _options
;
189 const ld::Atom
* _chosen
;
190 bool _reportDuplicate
;
191 bool _ignoreDuplicates
;
193 void pickAtom(const ld::Atom
& atom
) { _chosen
= &atom
; } // primitive to set which atom is picked
194 void pickAtomA() { pickAtom(_atomA
); } // primitive to pick atom A
195 void pickAtomB() { pickAtom(_atomB
); } // primitive to pick atom B
197 // use atom A if pickA, otherwise use atom B
198 void pickAOrB(bool pickA
) { if (pickA
) pickAtomA(); else pickAtomB(); }
200 void pickHigherOrdinal() {
201 pickAOrB(_atomA
.file()->ordinal() < _atomB
.file()->ordinal());
204 void pickLowerOrdinal() {
205 pickAOrB(_atomA
.file()->ordinal() > _atomB
.file()->ordinal());
208 void pickLargerSize() {
209 if (_atomA
.size() == _atomB
.size())
212 pickAOrB(_atomA
.size() > _atomB
.size());
215 void pickGreaterAlignment() {
216 pickAOrB(_atomA
.alignment().trailingZeros() > _atomB
.alignment().trailingZeros());
219 void pickBetweenRegularAtoms() {
220 if ( _atomA
.combine() == ld::Atom::combineByName
) {
221 if ( _atomB
.combine() == ld::Atom::combineByName
) {
222 // <rdar://problem/9183821> always choose mach-o over llvm bit code, otherwise LTO may eliminate the llvm atom
223 const bool aIsLTO
= (_atomA
.contentType() == ld::Atom::typeLTOtemporary
);
224 const bool bIsLTO
= (_atomB
.contentType() == ld::Atom::typeLTOtemporary
);
225 // <rdar://problem/9183821> always choose mach-o over llvm bit code, otherwise LTO may eliminate the llvm atom
226 if ( aIsLTO
!= bIsLTO
) {
230 // both weak, prefer non-auto-hide one
231 if ( _atomA
.autoHide() != _atomB
.autoHide() ) {
232 // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
233 pickAOrB(!_atomA
.autoHide());
235 else if ( _atomA
.autoHide() && _atomB
.autoHide() ) {
236 // both have auto-hide, so use one with greater alignment
237 pickGreaterAlignment();
240 // neither auto-hide, check visibility
241 if ( _atomA
.scope() != _atomB
.scope() ) {
242 // <rdar://problem/8304984> use more visible weak def symbol
243 pickAOrB(_atomA
.scope() == ld::Atom::scopeGlobal
);
246 // both have same visibility, use one with greater alignment
247 pickGreaterAlignment();
253 pickAtomB(); // pick not-weak
258 if ( _atomB
.combine() == ld::Atom::combineByName
) {
259 pickAtomA(); // pick not-weak
264 if ( _atomA
.section().type() == ld::Section::typeMachHeader
) {
267 else if ( _atomB
.section().type() == ld::Section::typeMachHeader
) {
271 if ( _ignoreDuplicates
) {
275 _reportDuplicate
= true;
282 void pickCommonsMode(const ld::Atom
& dylib
, const ld::Atom
& proxy
) {
283 assert(dylib
.definition() == ld::Atom::definitionTentative
);
284 assert(proxy
.definition() == ld::Atom::definitionProxy
);
285 switch ( _options
.commonsMode() ) {
286 case Options::kCommonsIgnoreDylibs
:
287 if ( _options
.warnCommons() )
288 warning("using common symbol %s from %s and ignoring defintion from dylib %s",
289 proxy
.name(), proxy
.file()->path(), dylib
.file()->path());
292 case Options::kCommonsOverriddenByDylibs
:
293 if ( _options
.warnCommons() )
294 warning("replacing common symbol %s from %s with true definition from dylib %s",
295 proxy
.name(), proxy
.file()->path(), dylib
.file()->path());
298 case Options::kCommonsConflictsDylibsError
:
299 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
300 proxy
.name(), proxy
.file()->path(), dylib
.file()->path());
304 void pickProxyAtom() {
305 // both atoms are definitionProxy
306 // <rdar://problem/5137732> ld should keep looking when it finds a weak definition in a dylib
307 if ( _atomA
.combine() == ld::Atom::combineByName
) {
309 } else if ( _atomB
.combine() == ld::Atom::combineByName
) {
312 throwf("symbol %s exported from both %s and %s\n", _atomA
.name(), _atomA
.file()->path(), _atomB
.file()->path());
317 // First, discriminate by definition
318 switch (_atomA
.definition()) {
319 case ld::Atom::definitionRegular
:
320 switch (_atomB
.definition()) {
321 case ld::Atom::definitionRegular
:
322 pickBetweenRegularAtoms();
324 case ld::Atom::definitionTentative
:
327 case ld::Atom::definitionAbsolute
:
328 _reportDuplicate
= true;
331 case ld::Atom::definitionProxy
:
336 case ld::Atom::definitionTentative
:
337 switch (_atomB
.definition()) {
338 case ld::Atom::definitionRegular
:
341 case ld::Atom::definitionTentative
:
344 case ld::Atom::definitionAbsolute
:
347 case ld::Atom::definitionProxy
:
348 pickCommonsMode(_atomA
, _atomB
);
352 case ld::Atom::definitionAbsolute
:
353 switch (_atomB
.definition()) {
354 case ld::Atom::definitionRegular
:
355 _reportDuplicate
= true;
358 case ld::Atom::definitionTentative
:
361 case ld::Atom::definitionAbsolute
:
362 _reportDuplicate
= true;
365 case ld::Atom::definitionProxy
:
370 case ld::Atom::definitionProxy
:
371 switch (_atomB
.definition()) {
372 case ld::Atom::definitionRegular
:
375 case ld::Atom::definitionTentative
:
376 pickCommonsMode(_atomB
, _atomA
);
378 case ld::Atom::definitionAbsolute
:
381 case ld::Atom::definitionProxy
:
390 bool SymbolTable::addByName(const ld::Atom
& newAtom
, bool ignoreDuplicates
)
393 assert(newAtom
.name() != NULL
);
394 const char* name
= newAtom
.name();
395 IndirectBindingSlot slot
= this->findSlotForName(name
);
396 const ld::Atom
* existingAtom
= _indirectBindingTable
[slot
];
397 //fprintf(stderr, "addByName(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
398 if ( existingAtom
!= NULL
) {
399 assert(&newAtom
!= existingAtom
);
400 NameCollisionResolution
picker(newAtom
, *existingAtom
, ignoreDuplicates
, _options
);
401 if (picker
.reportDuplicate()) {
402 addDuplicateSymbol(name
, existingAtom
);
403 addDuplicateSymbol(name
, &newAtom
);
405 useNew
= picker
.choseAtom(newAtom
);
408 _indirectBindingTable
[slot
] = &newAtom
;
409 if ( existingAtom
!= NULL
) {
410 markCoalescedAway(existingAtom
);
412 if ( newAtom
.scope() == ld::Atom::scopeGlobal
) {
413 if ( newAtom
.definition() == ld::Atom::definitionTentative
) {
414 _hasExternalTentativeDefinitions
= true;
419 markCoalescedAway(&newAtom
);
421 // return if existing atom in symbol table was replaced
422 return useNew
&& (existingAtom
!= NULL
);
426 bool SymbolTable::addByContent(const ld::Atom
& newAtom
)
429 const ld::Atom
* existingAtom
;
430 IndirectBindingSlot slot
= this->findSlotForContent(&newAtom
, &existingAtom
);
431 //fprintf(stderr, "addByContent(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
432 if ( existingAtom
!= NULL
) {
433 // use existing unless new one has greater alignment requirements
434 useNew
= ( newAtom
.alignment().trailingZeros() > existingAtom
->alignment().trailingZeros() );
437 _indirectBindingTable
[slot
] = &newAtom
;
438 if ( existingAtom
!= NULL
)
439 markCoalescedAway(existingAtom
);
442 _indirectBindingTable
[slot
] = existingAtom
;
443 if ( existingAtom
!= &newAtom
)
444 markCoalescedAway(&newAtom
);
446 // return if existing atom in symbol table was replaced
447 return useNew
&& (existingAtom
!= NULL
);
450 bool SymbolTable::addByReferences(const ld::Atom
& newAtom
)
453 const ld::Atom
* existingAtom
;
454 IndirectBindingSlot slot
= this->findSlotForReferences(&newAtom
, &existingAtom
);
455 //fprintf(stderr, "addByReferences(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
456 if ( existingAtom
!= NULL
) {
457 // use existing unless new one has greater alignment requirements
458 useNew
= ( newAtom
.alignment().trailingZeros() > existingAtom
->alignment().trailingZeros() );
461 _indirectBindingTable
[slot
] = &newAtom
;
462 if ( existingAtom
!= NULL
)
463 markCoalescedAway(existingAtom
);
466 if ( existingAtom
!= &newAtom
)
467 markCoalescedAway(&newAtom
);
469 // return if existing atom in symbol table was replaced
470 return useNew
&& (existingAtom
!= NULL
);
474 bool SymbolTable::add(const ld::Atom
& atom
, bool ignoreDuplicates
)
476 //fprintf(stderr, "SymbolTable::add(%p), name=%s\n", &atom, atom.name());
477 assert(atom
.scope() != ld::Atom::scopeTranslationUnit
);
478 switch ( atom
.combine() ) {
479 case ld::Atom::combineNever
:
480 case ld::Atom::combineByName
:
481 return this->addByName(atom
, ignoreDuplicates
);
483 case ld::Atom::combineByNameAndContent
:
484 return this->addByContent(atom
);
486 case ld::Atom::combineByNameAndReferences
:
487 return this->addByReferences(atom
);
494 void SymbolTable::markCoalescedAway(const ld::Atom
* atom
)
496 // remove this from list of all atoms used
497 //fprintf(stderr, "markCoalescedAway(%p) from %s\n", atom, atom->file()->path());
498 (const_cast<ld::Atom
*>(atom
))->setCoalescedAway();
501 // The fixupNoneGroupSubordinate* fixup kind is used to model group comdat.
502 // The "signature" atom in the group has a fixupNoneGroupSubordinate* fixup to
503 // all other members of the group. So, if the signature atom is
504 // coalesced away, all other atoms in the group should also be removed.
506 for (ld::Fixup::iterator fit
=atom
->fixupsBegin(), fend
=atom
->fixupsEnd(); fit
!= fend
; ++fit
) {
507 switch ( fit
->kind
) {
508 case ld::Fixup::kindNoneGroupSubordinate
:
509 case ld::Fixup::kindNoneGroupSubordinateFDE
:
510 case ld::Fixup::kindNoneGroupSubordinateLSDA
:
511 assert(fit
->binding
== ld::Fixup::bindingDirectlyBound
);
512 this->markCoalescedAway(fit
->u
.target
);
522 struct StrcmpSorter
{
523 bool operator() (const char* i
,const char* j
) {
528 return strcmp(i
, j
)<0;}
531 void SymbolTable::undefines(std::vector
<const char*>& undefs
)
533 // return all names in _byNameTable that have no associated atom
534 for (NameToSlot::iterator it
=_byNameTable
.begin(); it
!= _byNameTable
.end(); ++it
) {
535 //fprintf(stderr, " _byNameTable[%s] = slot %d which has atom %p\n", it->first, it->second, _indirectBindingTable[it->second]);
536 if ( _indirectBindingTable
[it
->second
] == NULL
)
537 undefs
.push_back(it
->first
);
539 // sort so that undefines are in a stable order (not dependent on hashing functions)
540 struct StrcmpSorter strcmpSorter
;
541 std::sort(undefs
.begin(), undefs
.end(), strcmpSorter
);
545 void SymbolTable::tentativeDefs(std::vector
<const char*>& tents
)
547 // return all names in _byNameTable that have no associated atom
548 for (NameToSlot::iterator it
=_byNameTable
.begin(); it
!= _byNameTable
.end(); ++it
) {
549 const char* name
= it
->first
;
550 const ld::Atom
* atom
= _indirectBindingTable
[it
->second
];
551 if ( (atom
!= NULL
) && (atom
->definition() == ld::Atom::definitionTentative
) )
552 tents
.push_back(name
);
554 std::sort(tents
.begin(), tents
.end());
558 bool SymbolTable::hasName(const char* name
)
560 NameToSlot::iterator pos
= _byNameTable
.find(name
);
561 if ( pos
== _byNameTable
.end() )
563 return (_indirectBindingTable
[pos
->second
] != NULL
);
566 // find existing or create new slot
567 SymbolTable::IndirectBindingSlot
SymbolTable::findSlotForName(const char* name
)
569 NameToSlot::iterator pos
= _byNameTable
.find(name
);
570 if ( pos
!= _byNameTable
.end() )
572 // create new slot for this name
573 SymbolTable::IndirectBindingSlot slot
= _indirectBindingTable
.size();
574 _indirectBindingTable
.push_back(NULL
);
575 _byNameTable
[name
] = slot
;
576 _byNameReverseTable
[slot
] = name
;
581 // find existing or create new slot
582 SymbolTable::IndirectBindingSlot
SymbolTable::findSlotForContent(const ld::Atom
* atom
, const ld::Atom
** existingAtom
)
584 //fprintf(stderr, "findSlotForContent(%p)\n", atom);
585 SymbolTable::IndirectBindingSlot slot
= 0;
586 UTF16StringToSlot::iterator upos
;
587 CStringToSlot::iterator cspos
;
588 ContentToSlot::iterator pos
;
589 switch ( atom
->section().type() ) {
590 case ld::Section::typeCString
:
591 cspos
= _cstringTable
.find(atom
);
592 if ( cspos
!= _cstringTable
.end() ) {
593 *existingAtom
= _indirectBindingTable
[cspos
->second
];
594 return cspos
->second
;
596 slot
= _indirectBindingTable
.size();
597 _cstringTable
[atom
] = slot
;
599 case ld::Section::typeNonStdCString
:
601 // use seg/sect name is key to map to avoid coalescing across segments and sections
603 sprintf(segsect
, "%s/%s", atom
->section().segmentName(), atom
->section().sectionName());
604 NameToMap::iterator mpos
= _nonStdCStringSectionToMap
.find(segsect
);
605 CStringToSlot
* map
= NULL
;
606 if ( mpos
== _nonStdCStringSectionToMap
.end() ) {
607 map
= new CStringToSlot();
608 _nonStdCStringSectionToMap
[strdup(segsect
)] = map
;
613 cspos
= map
->find(atom
);
614 if ( cspos
!= map
->end() ) {
615 *existingAtom
= _indirectBindingTable
[cspos
->second
];
616 return cspos
->second
;
618 slot
= _indirectBindingTable
.size();
619 map
->operator[](atom
) = slot
;
622 case ld::Section::typeUTF16Strings
:
623 upos
= _utf16Table
.find(atom
);
624 if ( upos
!= _utf16Table
.end() ) {
625 *existingAtom
= _indirectBindingTable
[upos
->second
];
628 slot
= _indirectBindingTable
.size();
629 _utf16Table
[atom
] = slot
;
631 case ld::Section::typeLiteral4
:
632 pos
= _literal4Table
.find(atom
);
633 if ( pos
!= _literal4Table
.end() ) {
634 *existingAtom
= _indirectBindingTable
[pos
->second
];
637 slot
= _indirectBindingTable
.size();
638 _literal4Table
[atom
] = slot
;
640 case ld::Section::typeLiteral8
:
641 pos
= _literal8Table
.find(atom
);
642 if ( pos
!= _literal8Table
.end() ) {
643 *existingAtom
= _indirectBindingTable
[pos
->second
];
646 slot
= _indirectBindingTable
.size();
647 _literal8Table
[atom
] = slot
;
649 case ld::Section::typeLiteral16
:
650 pos
= _literal16Table
.find(atom
);
651 if ( pos
!= _literal16Table
.end() ) {
652 *existingAtom
= _indirectBindingTable
[pos
->second
];
655 slot
= _indirectBindingTable
.size();
656 _literal16Table
[atom
] = slot
;
659 assert(0 && "section type does not support coalescing by content");
661 _indirectBindingTable
.push_back(atom
);
662 *existingAtom
= NULL
;
668 // find existing or create new slot
669 SymbolTable::IndirectBindingSlot
SymbolTable::findSlotForReferences(const ld::Atom
* atom
, const ld::Atom
** existingAtom
)
671 //fprintf(stderr, "findSlotForReferences(%p)\n", atom);
673 SymbolTable::IndirectBindingSlot slot
= 0;
674 ReferencesToSlot::iterator pos
;
675 switch ( atom
->section().type() ) {
676 case ld::Section::typeNonLazyPointer
:
677 pos
= _nonLazyPointerTable
.find(atom
);
678 if ( pos
!= _nonLazyPointerTable
.end() ) {
679 *existingAtom
= _indirectBindingTable
[pos
->second
];
682 slot
= _indirectBindingTable
.size();
683 _nonLazyPointerTable
[atom
] = slot
;
685 case ld::Section::typeCFString
:
686 pos
= _cfStringTable
.find(atom
);
687 if ( pos
!= _cfStringTable
.end() ) {
688 *existingAtom
= _indirectBindingTable
[pos
->second
];
691 slot
= _indirectBindingTable
.size();
692 _cfStringTable
[atom
] = slot
;
694 case ld::Section::typeObjCClassRefs
:
695 pos
= _objc2ClassRefTable
.find(atom
);
696 if ( pos
!= _objc2ClassRefTable
.end() ) {
697 *existingAtom
= _indirectBindingTable
[pos
->second
];
700 slot
= _indirectBindingTable
.size();
701 _objc2ClassRefTable
[atom
] = slot
;
703 case ld::Section::typeCStringPointer
:
704 pos
= _pointerToCStringTable
.find(atom
);
705 if ( pos
!= _pointerToCStringTable
.end() ) {
706 *existingAtom
= _indirectBindingTable
[pos
->second
];
709 slot
= _indirectBindingTable
.size();
710 _pointerToCStringTable
[atom
] = slot
;
713 assert(0 && "section type does not support coalescing by references");
715 _indirectBindingTable
.push_back(atom
);
716 *existingAtom
= NULL
;
721 const char* SymbolTable::indirectName(IndirectBindingSlot slot
) const
723 assert(slot
< _indirectBindingTable
.size());
724 const ld::Atom
* target
= _indirectBindingTable
[slot
];
725 if ( target
!= NULL
) {
726 return target
->name();
728 // handle case when by-name reference is indirected and no atom yet in _byNameTable
729 SlotToName::const_iterator pos
= _byNameReverseTable
.find(slot
);
730 if ( pos
!= _byNameReverseTable
.end() )
736 const ld::Atom
* SymbolTable::indirectAtom(IndirectBindingSlot slot
) const
738 assert(slot
< _indirectBindingTable
.size());
739 return _indirectBindingTable
[slot
];
742 void SymbolTable::printStatistics()
744 // fprintf(stderr, "cstring table size: %lu, bucket count: %lu, hash func called %u times\n",
745 // _cstringTable.size(), _cstringTable.bucket_count(), cstringHashCount);
747 for(unsigned int b
=0; b
< 11; ++b
) {
750 for(unsigned int i
=0; i
< _cstringTable
.bucket_count(); ++i
) {
751 unsigned int n
= _cstringTable
.elems_in_bucket(i
);
757 fprintf(stderr
, "cstring table distribution\n");
758 for(unsigned int b
=0; b
< 11; ++b
) {
759 fprintf(stderr
, "%u buckets have %u elements\n", count
[b
], b
);
761 fprintf(stderr
, "indirect table size: %lu\n", _indirectBindingTable
.size());
762 fprintf(stderr
, "by-name table size: %lu\n", _byNameTable
.size());
763 // fprintf(stderr, "by-content table size: %lu, hash count: %u, equals count: %u, lookup count: %u\n",
764 // _byContentTable.size(), contentHashCount, contentEqualCount, contentLookupCount);
765 // fprintf(stderr, "by-ref table size: %lu, hashed count: %u, equals count: %u, lookup count: %u, insert count: %u\n",
766 // _byReferencesTable.size(), refHashCount, refEqualsCount, refLookupCount, refInsertCount);
768 //ReferencesHash obj;
769 //for(ReferencesHashToSlot::iterator it=_byReferencesTable.begin(); it != _byReferencesTable.end(); ++it) {
770 // if ( obj.operator()(it->first) == 0x2F3AC0EAC744EA70 ) {
771 // fprintf(stderr, "hash=0x2F3AC0EAC744EA70 for %p %s from %s\n", it->first, it->first->name(), it->first->file()->path());