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 //fprintf(stderr, "pickAtom(), a=%p, def=%d, b=%p, def=%d\n", &_atomA, _atomA.definition(), &_atomB, _atomB.definition());
316 // First, discriminate by definition
317 switch (_atomA
.definition()) {
318 case ld::Atom::definitionRegular
:
319 switch (_atomB
.definition()) {
320 case ld::Atom::definitionRegular
:
321 pickBetweenRegularAtoms();
323 case ld::Atom::definitionTentative
:
324 if ( _atomB
.size() > _atomA
.size() ) {
325 const char* atomApath
= (_atomA
.file() != NULL
) ? _atomA
.file()->path() : "<internal>";
326 const char* atomBpath
= (_atomB
.file() != NULL
) ? _atomB
.file()->path() : "<internal>";
327 warning("tentative definition of '%s' with size %llu from '%s' is being replaced by real definition of smaller size %llu from '%s'",
328 _atomA
.name(), _atomB
.size(), atomBpath
, _atomA
.size(), atomApath
);
332 case ld::Atom::definitionAbsolute
:
333 _reportDuplicate
= true;
336 case ld::Atom::definitionProxy
:
341 case ld::Atom::definitionTentative
:
342 switch (_atomB
.definition()) {
343 case ld::Atom::definitionRegular
:
344 if ( _atomA
.size() > _atomB
.size() ) {
345 const char* atomApath
= (_atomA
.file() != NULL
) ? _atomA
.file()->path() : "<internal>";
346 const char* atomBpath
= (_atomB
.file() != NULL
) ? _atomB
.file()->path() : "<internal>";
347 warning("tentative definition of '%s' with size %llu from '%s' is being replaced by real definition of smaller size %llu from '%s'",
348 _atomA
.name(), _atomA
.size(),atomApath
, _atomB
.size(), atomBpath
);
352 case ld::Atom::definitionTentative
:
355 case ld::Atom::definitionAbsolute
:
358 case ld::Atom::definitionProxy
:
359 pickCommonsMode(_atomA
, _atomB
);
363 case ld::Atom::definitionAbsolute
:
364 switch (_atomB
.definition()) {
365 case ld::Atom::definitionRegular
:
366 _reportDuplicate
= true;
369 case ld::Atom::definitionTentative
:
372 case ld::Atom::definitionAbsolute
:
373 _reportDuplicate
= true;
376 case ld::Atom::definitionProxy
:
381 case ld::Atom::definitionProxy
:
382 switch (_atomB
.definition()) {
383 case ld::Atom::definitionRegular
:
386 case ld::Atom::definitionTentative
:
387 pickCommonsMode(_atomB
, _atomA
);
389 case ld::Atom::definitionAbsolute
:
392 case ld::Atom::definitionProxy
:
401 bool SymbolTable::addByName(const ld::Atom
& newAtom
, bool ignoreDuplicates
)
404 assert(newAtom
.name() != NULL
);
405 const char* name
= newAtom
.name();
406 IndirectBindingSlot slot
= this->findSlotForName(name
);
407 const ld::Atom
* existingAtom
= _indirectBindingTable
[slot
];
408 //fprintf(stderr, "addByName(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
409 if ( existingAtom
!= NULL
) {
410 assert(&newAtom
!= existingAtom
);
411 NameCollisionResolution
picker(newAtom
, *existingAtom
, ignoreDuplicates
, _options
);
412 if (picker
.reportDuplicate()) {
413 addDuplicateSymbol(name
, existingAtom
);
414 addDuplicateSymbol(name
, &newAtom
);
416 useNew
= picker
.choseAtom(newAtom
);
419 _indirectBindingTable
[slot
] = &newAtom
;
420 if ( existingAtom
!= NULL
) {
421 markCoalescedAway(existingAtom
);
423 if ( newAtom
.scope() == ld::Atom::scopeGlobal
) {
424 if ( newAtom
.definition() == ld::Atom::definitionTentative
) {
425 _hasExternalTentativeDefinitions
= true;
430 markCoalescedAway(&newAtom
);
432 // return if existing atom in symbol table was replaced
433 return useNew
&& (existingAtom
!= NULL
);
437 bool SymbolTable::addByContent(const ld::Atom
& newAtom
)
440 const ld::Atom
* existingAtom
;
441 IndirectBindingSlot slot
= this->findSlotForContent(&newAtom
, &existingAtom
);
442 //fprintf(stderr, "addByContent(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
443 if ( existingAtom
!= NULL
) {
444 // use existing unless new one has greater alignment requirements
445 useNew
= ( newAtom
.alignment().trailingZeros() > existingAtom
->alignment().trailingZeros() );
448 _indirectBindingTable
[slot
] = &newAtom
;
449 if ( existingAtom
!= NULL
)
450 markCoalescedAway(existingAtom
);
453 _indirectBindingTable
[slot
] = existingAtom
;
454 if ( existingAtom
!= &newAtom
)
455 markCoalescedAway(&newAtom
);
457 // return if existing atom in symbol table was replaced
458 return useNew
&& (existingAtom
!= NULL
);
461 bool SymbolTable::addByReferences(const ld::Atom
& newAtom
)
464 const ld::Atom
* existingAtom
;
465 IndirectBindingSlot slot
= this->findSlotForReferences(&newAtom
, &existingAtom
);
466 //fprintf(stderr, "addByReferences(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
467 if ( existingAtom
!= NULL
) {
468 // use existing unless new one has greater alignment requirements
469 useNew
= ( newAtom
.alignment().trailingZeros() > existingAtom
->alignment().trailingZeros() );
472 _indirectBindingTable
[slot
] = &newAtom
;
473 if ( existingAtom
!= NULL
)
474 markCoalescedAway(existingAtom
);
477 if ( existingAtom
!= &newAtom
)
478 markCoalescedAway(&newAtom
);
480 // return if existing atom in symbol table was replaced
481 return useNew
&& (existingAtom
!= NULL
);
485 bool SymbolTable::add(const ld::Atom
& atom
, bool ignoreDuplicates
)
487 //fprintf(stderr, "SymbolTable::add(%p), name=%s\n", &atom, atom.name());
488 assert(atom
.scope() != ld::Atom::scopeTranslationUnit
);
489 switch ( atom
.combine() ) {
490 case ld::Atom::combineNever
:
491 case ld::Atom::combineByName
:
492 return this->addByName(atom
, ignoreDuplicates
);
494 case ld::Atom::combineByNameAndContent
:
495 return this->addByContent(atom
);
497 case ld::Atom::combineByNameAndReferences
:
498 return this->addByReferences(atom
);
505 void SymbolTable::markCoalescedAway(const ld::Atom
* atom
)
507 // remove this from list of all atoms used
508 //fprintf(stderr, "markCoalescedAway(%p) from %s\n", atom, atom->file()->path());
509 (const_cast<ld::Atom
*>(atom
))->setCoalescedAway();
512 // The fixupNoneGroupSubordinate* fixup kind is used to model group comdat.
513 // The "signature" atom in the group has a fixupNoneGroupSubordinate* fixup to
514 // all other members of the group. So, if the signature atom is
515 // coalesced away, all other atoms in the group should also be removed.
517 for (ld::Fixup::iterator fit
=atom
->fixupsBegin(), fend
=atom
->fixupsEnd(); fit
!= fend
; ++fit
) {
518 switch ( fit
->kind
) {
519 case ld::Fixup::kindNoneGroupSubordinate
:
520 case ld::Fixup::kindNoneGroupSubordinateFDE
:
521 case ld::Fixup::kindNoneGroupSubordinateLSDA
:
522 assert(fit
->binding
== ld::Fixup::bindingDirectlyBound
);
523 this->markCoalescedAway(fit
->u
.target
);
533 struct StrcmpSorter
{
534 bool operator() (const char* i
,const char* j
) {
539 return strcmp(i
, j
)<0;}
542 void SymbolTable::undefines(std::vector
<const char*>& undefs
)
544 // return all names in _byNameTable that have no associated atom
545 for (NameToSlot::iterator it
=_byNameTable
.begin(); it
!= _byNameTable
.end(); ++it
) {
546 //fprintf(stderr, " _byNameTable[%s] = slot %d which has atom %p\n", it->first, it->second, _indirectBindingTable[it->second]);
547 if ( _indirectBindingTable
[it
->second
] == NULL
)
548 undefs
.push_back(it
->first
);
550 // sort so that undefines are in a stable order (not dependent on hashing functions)
551 struct StrcmpSorter strcmpSorter
;
552 std::sort(undefs
.begin(), undefs
.end(), strcmpSorter
);
556 void SymbolTable::tentativeDefs(std::vector
<const char*>& tents
)
558 // return all names in _byNameTable that have no associated atom
559 for (NameToSlot::iterator it
=_byNameTable
.begin(); it
!= _byNameTable
.end(); ++it
) {
560 const char* name
= it
->first
;
561 const ld::Atom
* atom
= _indirectBindingTable
[it
->second
];
562 if ( (atom
!= NULL
) && (atom
->definition() == ld::Atom::definitionTentative
) )
563 tents
.push_back(name
);
565 std::sort(tents
.begin(), tents
.end());
569 void SymbolTable::mustPreserveForBitcode(std::unordered_set
<const char*>& syms
)
571 // return all names in _byNameTable that have no associated atom
572 for (const auto &entry
: _byNameTable
) {
573 const char* name
= entry
.first
;
574 const ld::Atom
* atom
= _indirectBindingTable
[entry
.second
];
575 if ( (atom
== NULL
) || (atom
->definition() == ld::Atom::definitionProxy
) )
581 bool SymbolTable::hasName(const char* name
)
583 NameToSlot::iterator pos
= _byNameTable
.find(name
);
584 if ( pos
== _byNameTable
.end() )
586 return (_indirectBindingTable
[pos
->second
] != NULL
);
589 // find existing or create new slot
590 SymbolTable::IndirectBindingSlot
SymbolTable::findSlotForName(const char* name
)
592 NameToSlot::iterator pos
= _byNameTable
.find(name
);
593 if ( pos
!= _byNameTable
.end() )
595 // create new slot for this name
596 SymbolTable::IndirectBindingSlot slot
= _indirectBindingTable
.size();
597 _indirectBindingTable
.push_back(NULL
);
598 _byNameTable
[name
] = slot
;
599 _byNameReverseTable
[slot
] = name
;
603 void SymbolTable::removeDeadAtoms()
605 // remove dead atoms from: _byNameTable, _byNameReverseTable, and _indirectBindingTable
606 std::vector
<const char*> namesToRemove
;
607 for (NameToSlot::iterator it
=_byNameTable
.begin(); it
!= _byNameTable
.end(); ++it
) {
608 IndirectBindingSlot slot
= it
->second
;
609 const ld::Atom
* atom
= _indirectBindingTable
[slot
];
610 if ( atom
!= NULL
) {
611 if ( !atom
->live() && !atom
->dontDeadStrip() ) {
612 //fprintf(stderr, "removing from symbolTable[%u] %s\n", slot, atom->name());
613 _indirectBindingTable
[slot
] = NULL
;
614 // <rdar://problem/16025786> need to completely remove dead atoms from symbol table
615 _byNameReverseTable
.erase(slot
);
616 // can't remove while iterating, do it after iteration
617 namesToRemove
.push_back(it
->first
);
621 for (std::vector
<const char*>::iterator it
= namesToRemove
.begin(); it
!= namesToRemove
.end(); ++it
) {
622 _byNameTable
.erase(*it
);
625 // remove dead atoms from _nonLazyPointerTable
626 for (ReferencesToSlot::iterator it
=_nonLazyPointerTable
.begin(); it
!= _nonLazyPointerTable
.end(); ) {
627 const ld::Atom
* atom
= it
->first
;
628 assert(atom
!= NULL
);
629 if ( !atom
->live() && !atom
->dontDeadStrip() )
630 it
= _nonLazyPointerTable
.erase(it
);
635 // remove dead atoms from _cstringTable
636 for (CStringToSlot::iterator it
=_cstringTable
.begin(); it
!= _cstringTable
.end(); ) {
637 const ld::Atom
* atom
= it
->first
;
638 assert(atom
!= NULL
);
639 if ( !atom
->live() && !atom
->dontDeadStrip() )
640 it
= _cstringTable
.erase(it
);
645 // remove dead atoms from _utf16Table
646 for (UTF16StringToSlot::iterator it
=_utf16Table
.begin(); it
!= _utf16Table
.end(); ) {
647 const ld::Atom
* atom
= it
->first
;
648 assert(atom
!= NULL
);
649 if ( !atom
->live() && !atom
->dontDeadStrip() )
650 it
= _utf16Table
.erase(it
);
655 // remove dead atoms from _cfStringTable
656 for (ReferencesToSlot::iterator it
=_cfStringTable
.begin(); it
!= _cfStringTable
.end(); ) {
657 const ld::Atom
* atom
= it
->first
;
658 assert(atom
!= NULL
);
659 if ( !atom
->live() && !atom
->dontDeadStrip() )
660 it
= _cfStringTable
.erase(it
);
665 // remove dead atoms from _literal4Table
666 for (ContentToSlot::iterator it
=_literal4Table
.begin(); it
!= _literal4Table
.end(); ) {
667 const ld::Atom
* atom
= it
->first
;
668 assert(atom
!= NULL
);
669 if ( !atom
->live() && !atom
->dontDeadStrip() )
670 it
= _literal4Table
.erase(it
);
675 // remove dead atoms from _literal8Table
676 for (ContentToSlot::iterator it
=_literal8Table
.begin(); it
!= _literal8Table
.end(); ) {
677 const ld::Atom
* atom
= it
->first
;
678 assert(atom
!= NULL
);
679 if ( !atom
->live() && !atom
->dontDeadStrip() )
680 it
= _literal8Table
.erase(it
);
685 // remove dead atoms from _literal16Table
686 for (ContentToSlot::iterator it
=_literal16Table
.begin(); it
!= _literal16Table
.end(); ) {
687 const ld::Atom
* atom
= it
->first
;
688 assert(atom
!= NULL
);
689 if ( !atom
->live() && !atom
->dontDeadStrip() )
690 it
= _literal16Table
.erase(it
);
697 // find existing or create new slot
698 SymbolTable::IndirectBindingSlot
SymbolTable::findSlotForContent(const ld::Atom
* atom
, const ld::Atom
** existingAtom
)
700 //fprintf(stderr, "findSlotForContent(%p)\n", atom);
701 SymbolTable::IndirectBindingSlot slot
= 0;
702 UTF16StringToSlot::iterator upos
;
703 CStringToSlot::iterator cspos
;
704 ContentToSlot::iterator pos
;
705 switch ( atom
->section().type() ) {
706 case ld::Section::typeCString
:
707 cspos
= _cstringTable
.find(atom
);
708 if ( cspos
!= _cstringTable
.end() ) {
709 *existingAtom
= _indirectBindingTable
[cspos
->second
];
710 return cspos
->second
;
712 slot
= _indirectBindingTable
.size();
713 _cstringTable
[atom
] = slot
;
715 case ld::Section::typeNonStdCString
:
717 // use seg/sect name is key to map to avoid coalescing across segments and sections
719 sprintf(segsect
, "%s/%s", atom
->section().segmentName(), atom
->section().sectionName());
720 NameToMap::iterator mpos
= _nonStdCStringSectionToMap
.find(segsect
);
721 CStringToSlot
* map
= NULL
;
722 if ( mpos
== _nonStdCStringSectionToMap
.end() ) {
723 map
= new CStringToSlot();
724 _nonStdCStringSectionToMap
[strdup(segsect
)] = map
;
729 cspos
= map
->find(atom
);
730 if ( cspos
!= map
->end() ) {
731 *existingAtom
= _indirectBindingTable
[cspos
->second
];
732 return cspos
->second
;
734 slot
= _indirectBindingTable
.size();
735 map
->operator[](atom
) = slot
;
738 case ld::Section::typeUTF16Strings
:
739 upos
= _utf16Table
.find(atom
);
740 if ( upos
!= _utf16Table
.end() ) {
741 *existingAtom
= _indirectBindingTable
[upos
->second
];
744 slot
= _indirectBindingTable
.size();
745 _utf16Table
[atom
] = slot
;
747 case ld::Section::typeLiteral4
:
748 pos
= _literal4Table
.find(atom
);
749 if ( pos
!= _literal4Table
.end() ) {
750 *existingAtom
= _indirectBindingTable
[pos
->second
];
753 slot
= _indirectBindingTable
.size();
754 _literal4Table
[atom
] = slot
;
756 case ld::Section::typeLiteral8
:
757 pos
= _literal8Table
.find(atom
);
758 if ( pos
!= _literal8Table
.end() ) {
759 *existingAtom
= _indirectBindingTable
[pos
->second
];
762 slot
= _indirectBindingTable
.size();
763 _literal8Table
[atom
] = slot
;
765 case ld::Section::typeLiteral16
:
766 pos
= _literal16Table
.find(atom
);
767 if ( pos
!= _literal16Table
.end() ) {
768 *existingAtom
= _indirectBindingTable
[pos
->second
];
771 slot
= _indirectBindingTable
.size();
772 _literal16Table
[atom
] = slot
;
775 assert(0 && "section type does not support coalescing by content");
777 _indirectBindingTable
.push_back(atom
);
778 *existingAtom
= NULL
;
784 // find existing or create new slot
785 SymbolTable::IndirectBindingSlot
SymbolTable::findSlotForReferences(const ld::Atom
* atom
, const ld::Atom
** existingAtom
)
787 //fprintf(stderr, "findSlotForReferences(%p)\n", atom);
789 SymbolTable::IndirectBindingSlot slot
= 0;
790 ReferencesToSlot::iterator pos
;
791 switch ( atom
->section().type() ) {
792 case ld::Section::typeNonLazyPointer
:
793 pos
= _nonLazyPointerTable
.find(atom
);
794 if ( pos
!= _nonLazyPointerTable
.end() ) {
795 *existingAtom
= _indirectBindingTable
[pos
->second
];
798 slot
= _indirectBindingTable
.size();
799 _nonLazyPointerTable
[atom
] = slot
;
801 case ld::Section::typeCFString
:
802 pos
= _cfStringTable
.find(atom
);
803 if ( pos
!= _cfStringTable
.end() ) {
804 *existingAtom
= _indirectBindingTable
[pos
->second
];
807 slot
= _indirectBindingTable
.size();
808 _cfStringTable
[atom
] = slot
;
810 case ld::Section::typeObjCClassRefs
:
811 pos
= _objc2ClassRefTable
.find(atom
);
812 if ( pos
!= _objc2ClassRefTable
.end() ) {
813 *existingAtom
= _indirectBindingTable
[pos
->second
];
816 slot
= _indirectBindingTable
.size();
817 _objc2ClassRefTable
[atom
] = slot
;
819 case ld::Section::typeCStringPointer
:
820 pos
= _pointerToCStringTable
.find(atom
);
821 if ( pos
!= _pointerToCStringTable
.end() ) {
822 *existingAtom
= _indirectBindingTable
[pos
->second
];
825 slot
= _indirectBindingTable
.size();
826 _pointerToCStringTable
[atom
] = slot
;
828 case ld::Section::typeTLVPointers
:
829 pos
= _threadPointerTable
.find(atom
);
830 if ( pos
!= _threadPointerTable
.end() ) {
831 *existingAtom
= _indirectBindingTable
[pos
->second
];
834 slot
= _indirectBindingTable
.size();
835 _threadPointerTable
[atom
] = slot
;
838 assert(0 && "section type does not support coalescing by references");
840 _indirectBindingTable
.push_back(atom
);
841 *existingAtom
= NULL
;
846 const char* SymbolTable::indirectName(IndirectBindingSlot slot
) const
848 assert(slot
< _indirectBindingTable
.size());
849 const ld::Atom
* target
= _indirectBindingTable
[slot
];
850 if ( target
!= NULL
) {
851 return target
->name();
853 // handle case when by-name reference is indirected and no atom yet in _byNameTable
854 SlotToName::const_iterator pos
= _byNameReverseTable
.find(slot
);
855 if ( pos
!= _byNameReverseTable
.end() )
861 const ld::Atom
* SymbolTable::indirectAtom(IndirectBindingSlot slot
) const
863 assert(slot
< _indirectBindingTable
.size());
864 return _indirectBindingTable
[slot
];
867 void SymbolTable::printStatistics()
869 // fprintf(stderr, "cstring table size: %lu, bucket count: %lu, hash func called %u times\n",
870 // _cstringTable.size(), _cstringTable.bucket_count(), cstringHashCount);
872 for(unsigned int b
=0; b
< 11; ++b
) {
875 for(unsigned int i
=0; i
< _cstringTable
.bucket_count(); ++i
) {
876 unsigned int n
= _cstringTable
.bucket_size(i
);
882 fprintf(stderr
, "cstring table distribution\n");
883 for(unsigned int b
=0; b
< 11; ++b
) {
884 fprintf(stderr
, "%u buckets have %u elements\n", count
[b
], b
);
886 fprintf(stderr
, "indirect table size: %lu\n", _indirectBindingTable
.size());
887 fprintf(stderr
, "by-name table size: %lu\n", _byNameTable
.size());
888 // fprintf(stderr, "by-content table size: %lu, hash count: %u, equals count: %u, lookup count: %u\n",
889 // _byContentTable.size(), contentHashCount, contentEqualCount, contentLookupCount);
890 // fprintf(stderr, "by-ref table size: %lu, hashed count: %u, equals count: %u, lookup count: %u, insert count: %u\n",
891 // _byReferencesTable.size(), refHashCount, refEqualsCount, refLookupCount, refInsertCount);
893 //ReferencesHash obj;
894 //for(ReferencesHashToSlot::iterator it=_byReferencesTable.begin(); it != _byReferencesTable.end(); ++it) {
895 // if ( obj.operator()(it->first) == 0x2F3AC0EAC744EA70 ) {
896 // fprintf(stderr, "hash=0x2F3AC0EAC744EA70 for %p %s from %s\n", it->first, it->first->name(), it->first->file()->path());