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>
48 #include "InputFiles.h"
49 #include "SymbolTable.h"
57 // HACK, I can't find a way to pass values in the compare classes (e.g. ContentFuncs)
58 // so use global variable to pass info.
59 static ld::IndirectBindingTable
* _s_indirectBindingTable
= NULL
;
62 SymbolTable::SymbolTable(const Options
& opts
, std::vector
<const ld::Atom
*>& ibt
)
63 : _options(opts
), _cstringTable(6151), _indirectBindingTable(ibt
), _hasExternalTentativeDefinitions(false)
65 _s_indirectBindingTable
= this;
69 size_t SymbolTable::ContentFuncs::operator()(const ld::Atom
* atom
) const
71 return atom
->contentHash(*_s_indirectBindingTable
);
74 bool SymbolTable::ContentFuncs::operator()(const ld::Atom
* left
, const ld::Atom
* right
) const
76 return (memcmp(left
->rawContentPointer(), right
->rawContentPointer(), left
->size()) == 0);
81 size_t SymbolTable::CStringHashFuncs::operator()(const ld::Atom
* atom
) const
83 return atom
->contentHash(*_s_indirectBindingTable
);
86 bool SymbolTable::CStringHashFuncs::operator()(const ld::Atom
* left
, const ld::Atom
* right
) const
88 return (strcmp((char*)left
->rawContentPointer(), (char*)right
->rawContentPointer()) == 0);
92 size_t SymbolTable::UTF16StringHashFuncs::operator()(const ld::Atom
* atom
) const
94 return atom
->contentHash(*_s_indirectBindingTable
);
97 bool SymbolTable::UTF16StringHashFuncs::operator()(const ld::Atom
* left
, const ld::Atom
* right
) const
101 const void* leftContent
= left
->rawContentPointer();
102 const void* rightContent
= right
->rawContentPointer();
103 unsigned int amount
= left
->size()-2;
104 bool result
= (memcmp(leftContent
, rightContent
, amount
) == 0);
109 size_t SymbolTable::ReferencesHashFuncs::operator()(const ld::Atom
* atom
) const
111 return atom
->contentHash(*_s_indirectBindingTable
);
114 bool SymbolTable::ReferencesHashFuncs::operator()(const ld::Atom
* left
, const ld::Atom
* right
) const
116 return left
->canCoalesceWith(*right
, *_s_indirectBindingTable
);
120 void SymbolTable::addDuplicateSymbol(const char *name
, const ld::Atom
*atom
)
122 // Look up or create the file list for name.
123 DuplicateSymbols::iterator symbolsIterator
= _duplicateSymbols
.find(name
);
124 DuplicatedSymbolAtomList
*atoms
= NULL
;
125 if (symbolsIterator
!= _duplicateSymbols
.end()) {
126 atoms
= symbolsIterator
->second
;
128 atoms
= new std::vector
<const ld::Atom
*>;
129 _duplicateSymbols
.insert(std::pair
<const char *, DuplicatedSymbolAtomList
*>(name
, atoms
));
132 // check if file is already in the list, add it if not
134 for (DuplicatedSymbolAtomList::iterator it
= atoms
->begin(); !found
&& it
!= atoms
->end(); it
++)
135 if (strcmp((*it
)->file()->path(), atom
->file()->path()) == 0)
138 atoms
->push_back(atom
);
141 void SymbolTable::checkDuplicateSymbols() const
143 bool foundDuplicate
= false;
144 for (DuplicateSymbols::const_iterator symbolIt
= _duplicateSymbols
.begin(); symbolIt
!= _duplicateSymbols
.end(); symbolIt
++) {
145 DuplicatedSymbolAtomList
*atoms
= symbolIt
->second
;
146 bool reportDuplicate
;
147 if (_options
.deadCodeStrip()) {
148 // search for a live atom
149 reportDuplicate
= false;
150 for (DuplicatedSymbolAtomList::iterator it
= atoms
->begin(); !reportDuplicate
&& it
!= atoms
->end(); it
++) {
152 reportDuplicate
= true;
155 reportDuplicate
= true;
157 if (reportDuplicate
) {
158 foundDuplicate
= true;
159 fprintf(stderr
, "duplicate symbol %s in:\n", symbolIt
->first
);
160 for (DuplicatedSymbolAtomList::iterator atomIt
= atoms
->begin(); atomIt
!= atoms
->end(); atomIt
++) {
161 fprintf(stderr
, " %s\n", (*atomIt
)->file()->path());
166 throwf("%d duplicate symbol%s", (int)_duplicateSymbols
.size(), _duplicateSymbols
.size()==1?"":"s");
169 // AtomPicker encapsulates the logic for picking which atom to use when adding an atom by name results in a collision
170 class NameCollisionResolution
{
172 NameCollisionResolution(const ld::Atom
& a
, const ld::Atom
& b
, bool ignoreDuplicates
, const Options
& options
) : _atomA(a
), _atomB(b
), _options(options
), _reportDuplicate(false), _ignoreDuplicates(ignoreDuplicates
) {
176 // Returns which atom to use
177 const ld::Atom
& chosen() { return *_chosen
; }
178 bool choseAtom(const ld::Atom
& atom
) { return _chosen
== &atom
; }
180 // Returns true if the two atoms should be reported as a duplicate symbol
181 bool reportDuplicate() { return _reportDuplicate
; }
184 const ld::Atom
& _atomA
;
185 const ld::Atom
& _atomB
;
186 const Options
& _options
;
187 const ld::Atom
* _chosen
;
188 bool _reportDuplicate
;
189 bool _ignoreDuplicates
;
191 void pickAtom(const ld::Atom
& atom
) { _chosen
= &atom
; } // primitive to set which atom is picked
192 void pickAtomA() { pickAtom(_atomA
); } // primitive to pick atom A
193 void pickAtomB() { pickAtom(_atomB
); } // primitive to pick atom B
195 // use atom A if pickA, otherwise use atom B
196 void pickAOrB(bool pickA
) { if (pickA
) pickAtomA(); else pickAtomB(); }
198 void pickHigherOrdinal() {
199 pickAOrB(_atomA
.file()->ordinal() < _atomB
.file()->ordinal());
202 void pickLowerOrdinal() {
203 pickAOrB(_atomA
.file()->ordinal() > _atomB
.file()->ordinal());
206 void pickLargerSize() {
207 if (_atomA
.size() == _atomB
.size())
210 pickAOrB(_atomA
.size() > _atomB
.size());
213 void pickGreaterAlignment() {
214 pickAOrB(_atomA
.alignment().trailingZeros() > _atomB
.alignment().trailingZeros());
217 void pickBetweenRegularAtoms() {
218 if ( _atomA
.combine() == ld::Atom::combineByName
) {
219 if ( _atomB
.combine() == ld::Atom::combineByName
) {
220 // <rdar://problem/9183821> always choose mach-o over llvm bit code, otherwise LTO may eliminate the llvm atom
221 const bool aIsLTO
= (_atomA
.contentType() == ld::Atom::typeLTOtemporary
);
222 const bool bIsLTO
= (_atomB
.contentType() == ld::Atom::typeLTOtemporary
);
223 // <rdar://problem/9183821> always choose mach-o over llvm bit code, otherwise LTO may eliminate the llvm atom
224 if ( aIsLTO
!= bIsLTO
) {
228 // both weak, prefer non-auto-hide one
229 if ( _atomA
.autoHide() != _atomB
.autoHide() ) {
230 // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
231 pickAOrB(!_atomA
.autoHide());
233 else if ( _atomA
.autoHide() && _atomB
.autoHide() ) {
234 // both have auto-hide, so use one with greater alignment
235 pickGreaterAlignment();
238 // neither auto-hide, check visibility
239 if ( _atomA
.scope() != _atomB
.scope() ) {
240 // <rdar://problem/8304984> use more visible weak def symbol
241 pickAOrB(_atomA
.scope() == ld::Atom::scopeGlobal
);
244 // both have same visibility, use one with greater alignment
245 pickGreaterAlignment();
251 pickAtomB(); // pick not-weak
256 if ( _atomB
.combine() == ld::Atom::combineByName
) {
257 pickAtomA(); // pick not-weak
262 if ( _atomA
.section().type() == ld::Section::typeMachHeader
) {
265 else if ( _atomB
.section().type() == ld::Section::typeMachHeader
) {
269 if ( _ignoreDuplicates
) {
273 _reportDuplicate
= true;
280 void pickCommonsMode(const ld::Atom
& dylib
, const ld::Atom
& proxy
) {
281 assert(dylib
.definition() == ld::Atom::definitionTentative
);
282 assert(proxy
.definition() == ld::Atom::definitionProxy
);
283 switch ( _options
.commonsMode() ) {
284 case Options::kCommonsIgnoreDylibs
:
285 if ( _options
.warnCommons() )
286 warning("using common symbol %s from %s and ignoring defintion from dylib %s",
287 proxy
.name(), proxy
.file()->path(), dylib
.file()->path());
290 case Options::kCommonsOverriddenByDylibs
:
291 if ( _options
.warnCommons() )
292 warning("replacing common symbol %s from %s with true definition from dylib %s",
293 proxy
.name(), proxy
.file()->path(), dylib
.file()->path());
296 case Options::kCommonsConflictsDylibsError
:
297 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
298 proxy
.name(), proxy
.file()->path(), dylib
.file()->path());
302 void pickProxyAtom() {
303 // both atoms are definitionProxy
304 // <rdar://problem/5137732> ld should keep looking when it finds a weak definition in a dylib
305 if ( _atomA
.combine() == ld::Atom::combineByName
) {
307 } else if ( _atomB
.combine() == ld::Atom::combineByName
) {
310 throwf("symbol %s exported from both %s and %s\n", _atomA
.name(), _atomA
.file()->path(), _atomB
.file()->path());
315 // First, discriminate by definition
316 switch (_atomA
.definition()) {
317 case ld::Atom::definitionRegular
:
318 switch (_atomB
.definition()) {
319 case ld::Atom::definitionRegular
:
320 pickBetweenRegularAtoms();
322 case ld::Atom::definitionTentative
:
325 case ld::Atom::definitionAbsolute
:
326 _reportDuplicate
= true;
329 case ld::Atom::definitionProxy
:
334 case ld::Atom::definitionTentative
:
335 switch (_atomB
.definition()) {
336 case ld::Atom::definitionRegular
:
339 case ld::Atom::definitionTentative
:
342 case ld::Atom::definitionAbsolute
:
345 case ld::Atom::definitionProxy
:
346 pickCommonsMode(_atomA
, _atomB
);
350 case ld::Atom::definitionAbsolute
:
351 switch (_atomB
.definition()) {
352 case ld::Atom::definitionRegular
:
353 _reportDuplicate
= true;
356 case ld::Atom::definitionTentative
:
359 case ld::Atom::definitionAbsolute
:
360 _reportDuplicate
= true;
363 case ld::Atom::definitionProxy
:
368 case ld::Atom::definitionProxy
:
369 switch (_atomB
.definition()) {
370 case ld::Atom::definitionRegular
:
373 case ld::Atom::definitionTentative
:
374 pickCommonsMode(_atomB
, _atomA
);
376 case ld::Atom::definitionAbsolute
:
379 case ld::Atom::definitionProxy
:
388 bool SymbolTable::addByName(const ld::Atom
& newAtom
, bool ignoreDuplicates
)
391 assert(newAtom
.name() != NULL
);
392 const char* name
= newAtom
.name();
393 IndirectBindingSlot slot
= this->findSlotForName(name
);
394 const ld::Atom
* existingAtom
= _indirectBindingTable
[slot
];
395 //fprintf(stderr, "addByName(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
396 if ( existingAtom
!= NULL
) {
397 assert(&newAtom
!= existingAtom
);
398 NameCollisionResolution
picker(newAtom
, *existingAtom
, ignoreDuplicates
, _options
);
399 if (picker
.reportDuplicate()) {
400 addDuplicateSymbol(name
, existingAtom
);
401 addDuplicateSymbol(name
, &newAtom
);
403 useNew
= picker
.choseAtom(newAtom
);
406 _indirectBindingTable
[slot
] = &newAtom
;
407 if ( existingAtom
!= NULL
) {
408 markCoalescedAway(existingAtom
);
410 if ( newAtom
.scope() == ld::Atom::scopeGlobal
) {
411 if ( newAtom
.definition() == ld::Atom::definitionTentative
) {
412 _hasExternalTentativeDefinitions
= true;
417 markCoalescedAway(&newAtom
);
419 // return if existing atom in symbol table was replaced
420 return useNew
&& (existingAtom
!= NULL
);
424 bool SymbolTable::addByContent(const ld::Atom
& newAtom
)
427 const ld::Atom
* existingAtom
;
428 IndirectBindingSlot slot
= this->findSlotForContent(&newAtom
, &existingAtom
);
429 //fprintf(stderr, "addByContent(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
430 if ( existingAtom
!= NULL
) {
431 // use existing unless new one has greater alignment requirements
432 useNew
= ( newAtom
.alignment().trailingZeros() > existingAtom
->alignment().trailingZeros() );
435 _indirectBindingTable
[slot
] = &newAtom
;
436 if ( existingAtom
!= NULL
)
437 markCoalescedAway(existingAtom
);
440 _indirectBindingTable
[slot
] = existingAtom
;
441 if ( existingAtom
!= &newAtom
)
442 markCoalescedAway(&newAtom
);
444 // return if existing atom in symbol table was replaced
445 return useNew
&& (existingAtom
!= NULL
);
448 bool SymbolTable::addByReferences(const ld::Atom
& newAtom
)
451 const ld::Atom
* existingAtom
;
452 IndirectBindingSlot slot
= this->findSlotForReferences(&newAtom
, &existingAtom
);
453 //fprintf(stderr, "addByReferences(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
454 if ( existingAtom
!= NULL
) {
455 // use existing unless new one has greater alignment requirements
456 useNew
= ( newAtom
.alignment().trailingZeros() > existingAtom
->alignment().trailingZeros() );
459 _indirectBindingTable
[slot
] = &newAtom
;
460 if ( existingAtom
!= NULL
)
461 markCoalescedAway(existingAtom
);
464 if ( existingAtom
!= &newAtom
)
465 markCoalescedAway(&newAtom
);
467 // return if existing atom in symbol table was replaced
468 return useNew
&& (existingAtom
!= NULL
);
472 bool SymbolTable::add(const ld::Atom
& atom
, bool ignoreDuplicates
)
474 //fprintf(stderr, "SymbolTable::add(%p), name=%s\n", &atom, atom.name());
475 assert(atom
.scope() != ld::Atom::scopeTranslationUnit
);
476 switch ( atom
.combine() ) {
477 case ld::Atom::combineNever
:
478 case ld::Atom::combineByName
:
479 return this->addByName(atom
, ignoreDuplicates
);
481 case ld::Atom::combineByNameAndContent
:
482 return this->addByContent(atom
);
484 case ld::Atom::combineByNameAndReferences
:
485 return this->addByReferences(atom
);
492 void SymbolTable::markCoalescedAway(const ld::Atom
* atom
)
494 // remove this from list of all atoms used
495 //fprintf(stderr, "markCoalescedAway(%p) from %s\n", atom, atom->file()->path());
496 (const_cast<ld::Atom
*>(atom
))->setCoalescedAway();
499 // The fixupNoneGroupSubordinate* fixup kind is used to model group comdat.
500 // The "signature" atom in the group has a fixupNoneGroupSubordinate* fixup to
501 // all other members of the group. So, if the signature atom is
502 // coalesced away, all other atoms in the group should also be removed.
504 for (ld::Fixup::iterator fit
=atom
->fixupsBegin(), fend
=atom
->fixupsEnd(); fit
!= fend
; ++fit
) {
505 switch ( fit
->kind
) {
506 case ld::Fixup::kindNoneGroupSubordinate
:
507 case ld::Fixup::kindNoneGroupSubordinateFDE
:
508 case ld::Fixup::kindNoneGroupSubordinateLSDA
:
509 assert(fit
->binding
== ld::Fixup::bindingDirectlyBound
);
510 this->markCoalescedAway(fit
->u
.target
);
520 struct StrcmpSorter
{
521 bool operator() (const char* i
,const char* j
) {
526 return strcmp(i
, j
)<0;}
529 void SymbolTable::undefines(std::vector
<const char*>& undefs
)
531 // return all names in _byNameTable that have no associated atom
532 for (NameToSlot::iterator it
=_byNameTable
.begin(); it
!= _byNameTable
.end(); ++it
) {
533 //fprintf(stderr, " _byNameTable[%s] = slot %d which has atom %p\n", it->first, it->second, _indirectBindingTable[it->second]);
534 if ( _indirectBindingTable
[it
->second
] == NULL
)
535 undefs
.push_back(it
->first
);
537 // sort so that undefines are in a stable order (not dependent on hashing functions)
538 struct StrcmpSorter strcmpSorter
;
539 std::sort(undefs
.begin(), undefs
.end(), strcmpSorter
);
543 void SymbolTable::tentativeDefs(std::vector
<const char*>& tents
)
545 // return all names in _byNameTable that have no associated atom
546 for (NameToSlot::iterator it
=_byNameTable
.begin(); it
!= _byNameTable
.end(); ++it
) {
547 const char* name
= it
->first
;
548 const ld::Atom
* atom
= _indirectBindingTable
[it
->second
];
549 if ( (atom
!= NULL
) && (atom
->definition() == ld::Atom::definitionTentative
) )
550 tents
.push_back(name
);
552 std::sort(tents
.begin(), tents
.end());
556 bool SymbolTable::hasName(const char* name
)
558 NameToSlot::iterator pos
= _byNameTable
.find(name
);
559 if ( pos
== _byNameTable
.end() )
561 return (_indirectBindingTable
[pos
->second
] != NULL
);
564 // find existing or create new slot
565 SymbolTable::IndirectBindingSlot
SymbolTable::findSlotForName(const char* name
)
567 NameToSlot::iterator pos
= _byNameTable
.find(name
);
568 if ( pos
!= _byNameTable
.end() )
570 // create new slot for this name
571 SymbolTable::IndirectBindingSlot slot
= _indirectBindingTable
.size();
572 _indirectBindingTable
.push_back(NULL
);
573 _byNameTable
[name
] = slot
;
574 _byNameReverseTable
[slot
] = name
;
579 // find existing or create new slot
580 SymbolTable::IndirectBindingSlot
SymbolTable::findSlotForContent(const ld::Atom
* atom
, const ld::Atom
** existingAtom
)
582 //fprintf(stderr, "findSlotForContent(%p)\n", atom);
583 SymbolTable::IndirectBindingSlot slot
= 0;
584 UTF16StringToSlot::iterator upos
;
585 CStringToSlot::iterator cspos
;
586 ContentToSlot::iterator pos
;
587 switch ( atom
->section().type() ) {
588 case ld::Section::typeCString
:
589 cspos
= _cstringTable
.find(atom
);
590 if ( cspos
!= _cstringTable
.end() ) {
591 *existingAtom
= _indirectBindingTable
[cspos
->second
];
592 return cspos
->second
;
594 slot
= _indirectBindingTable
.size();
595 _cstringTable
[atom
] = slot
;
597 case ld::Section::typeNonStdCString
:
599 // use seg/sect name is key to map to avoid coalescing across segments and sections
601 sprintf(segsect
, "%s/%s", atom
->section().segmentName(), atom
->section().sectionName());
602 NameToMap::iterator mpos
= _nonStdCStringSectionToMap
.find(segsect
);
603 CStringToSlot
* map
= NULL
;
604 if ( mpos
== _nonStdCStringSectionToMap
.end() ) {
605 map
= new CStringToSlot();
606 _nonStdCStringSectionToMap
[strdup(segsect
)] = map
;
611 cspos
= map
->find(atom
);
612 if ( cspos
!= map
->end() ) {
613 *existingAtom
= _indirectBindingTable
[cspos
->second
];
614 return cspos
->second
;
616 slot
= _indirectBindingTable
.size();
617 map
->operator[](atom
) = slot
;
620 case ld::Section::typeUTF16Strings
:
621 upos
= _utf16Table
.find(atom
);
622 if ( upos
!= _utf16Table
.end() ) {
623 *existingAtom
= _indirectBindingTable
[upos
->second
];
626 slot
= _indirectBindingTable
.size();
627 _utf16Table
[atom
] = slot
;
629 case ld::Section::typeLiteral4
:
630 pos
= _literal4Table
.find(atom
);
631 if ( pos
!= _literal4Table
.end() ) {
632 *existingAtom
= _indirectBindingTable
[pos
->second
];
635 slot
= _indirectBindingTable
.size();
636 _literal4Table
[atom
] = slot
;
638 case ld::Section::typeLiteral8
:
639 pos
= _literal8Table
.find(atom
);
640 if ( pos
!= _literal8Table
.end() ) {
641 *existingAtom
= _indirectBindingTable
[pos
->second
];
644 slot
= _indirectBindingTable
.size();
645 _literal8Table
[atom
] = slot
;
647 case ld::Section::typeLiteral16
:
648 pos
= _literal16Table
.find(atom
);
649 if ( pos
!= _literal16Table
.end() ) {
650 *existingAtom
= _indirectBindingTable
[pos
->second
];
653 slot
= _indirectBindingTable
.size();
654 _literal16Table
[atom
] = slot
;
657 assert(0 && "section type does not support coalescing by content");
659 _indirectBindingTable
.push_back(atom
);
660 *existingAtom
= NULL
;
666 // find existing or create new slot
667 SymbolTable::IndirectBindingSlot
SymbolTable::findSlotForReferences(const ld::Atom
* atom
, const ld::Atom
** existingAtom
)
669 //fprintf(stderr, "findSlotForReferences(%p)\n", atom);
671 SymbolTable::IndirectBindingSlot slot
= 0;
672 ReferencesToSlot::iterator pos
;
673 switch ( atom
->section().type() ) {
674 case ld::Section::typeNonLazyPointer
:
675 pos
= _nonLazyPointerTable
.find(atom
);
676 if ( pos
!= _nonLazyPointerTable
.end() ) {
677 *existingAtom
= _indirectBindingTable
[pos
->second
];
680 slot
= _indirectBindingTable
.size();
681 _nonLazyPointerTable
[atom
] = slot
;
683 case ld::Section::typeCFString
:
684 pos
= _cfStringTable
.find(atom
);
685 if ( pos
!= _cfStringTable
.end() ) {
686 *existingAtom
= _indirectBindingTable
[pos
->second
];
689 slot
= _indirectBindingTable
.size();
690 _cfStringTable
[atom
] = slot
;
692 case ld::Section::typeObjCClassRefs
:
693 pos
= _objc2ClassRefTable
.find(atom
);
694 if ( pos
!= _objc2ClassRefTable
.end() ) {
695 *existingAtom
= _indirectBindingTable
[pos
->second
];
698 slot
= _indirectBindingTable
.size();
699 _objc2ClassRefTable
[atom
] = slot
;
701 case ld::Section::typeCStringPointer
:
702 pos
= _pointerToCStringTable
.find(atom
);
703 if ( pos
!= _pointerToCStringTable
.end() ) {
704 *existingAtom
= _indirectBindingTable
[pos
->second
];
707 slot
= _indirectBindingTable
.size();
708 _pointerToCStringTable
[atom
] = slot
;
711 assert(0 && "section type does not support coalescing by references");
713 _indirectBindingTable
.push_back(atom
);
714 *existingAtom
= NULL
;
719 const char* SymbolTable::indirectName(IndirectBindingSlot slot
) const
721 assert(slot
< _indirectBindingTable
.size());
722 const ld::Atom
* target
= _indirectBindingTable
[slot
];
723 if ( target
!= NULL
) {
724 return target
->name();
726 // handle case when by-name reference is indirected and no atom yet in _byNameTable
727 SlotToName::const_iterator pos
= _byNameReverseTable
.find(slot
);
728 if ( pos
!= _byNameReverseTable
.end() )
734 const ld::Atom
* SymbolTable::indirectAtom(IndirectBindingSlot slot
) const
736 assert(slot
< _indirectBindingTable
.size());
737 return _indirectBindingTable
[slot
];
740 void SymbolTable::printStatistics()
742 // fprintf(stderr, "cstring table size: %lu, bucket count: %lu, hash func called %u times\n",
743 // _cstringTable.size(), _cstringTable.bucket_count(), cstringHashCount);
745 for(unsigned int b
=0; b
< 11; ++b
) {
748 for(unsigned int i
=0; i
< _cstringTable
.bucket_count(); ++i
) {
749 unsigned int n
= _cstringTable
.bucket_size(i
);
755 fprintf(stderr
, "cstring table distribution\n");
756 for(unsigned int b
=0; b
< 11; ++b
) {
757 fprintf(stderr
, "%u buckets have %u elements\n", count
[b
], b
);
759 fprintf(stderr
, "indirect table size: %lu\n", _indirectBindingTable
.size());
760 fprintf(stderr
, "by-name table size: %lu\n", _byNameTable
.size());
761 // fprintf(stderr, "by-content table size: %lu, hash count: %u, equals count: %u, lookup count: %u\n",
762 // _byContentTable.size(), contentHashCount, contentEqualCount, contentLookupCount);
763 // fprintf(stderr, "by-ref table size: %lu, hashed count: %u, equals count: %u, lookup count: %u, insert count: %u\n",
764 // _byReferencesTable.size(), refHashCount, refEqualsCount, refLookupCount, refInsertCount);
766 //ReferencesHash obj;
767 //for(ReferencesHashToSlot::iterator it=_byReferencesTable.begin(); it != _byReferencesTable.end(); ++it) {
768 // if ( obj.operator()(it->first) == 0x2F3AC0EAC744EA70 ) {
769 // fprintf(stderr, "hash=0x2F3AC0EAC744EA70 for %p %s from %s\n", it->first, it->first->name(), it->first->file()->path());