#include <set>
#include <vector>
#include <algorithm>
-#include <ext/hash_map>
-#include <ext/hash_set>
#include "Options.h"
// check if file is already in the list, add it if not
bool found = false;
for (DuplicatedSymbolAtomList::iterator it = atoms->begin(); !found && it != atoms->end(); it++)
- if (strcmp((*it)->file()->path(), atom->file()->path()) == 0)
+ if (strcmp((*it)->safeFilePath(), atom->safeFilePath()) == 0)
found = true;
if (!found)
atoms->push_back(atom);
foundDuplicate = true;
fprintf(stderr, "duplicate symbol %s in:\n", symbolIt->first);
for (DuplicatedSymbolAtomList::iterator atomIt = atoms->begin(); atomIt != atoms->end(); atomIt++) {
- fprintf(stderr, " %s\n", (*atomIt)->file()->path());
+ fprintf(stderr, " %s\n", (*atomIt)->safeFilePath());
}
}
}
case Options::kCommonsIgnoreDylibs:
if ( _options.warnCommons() )
warning("using common symbol %s from %s and ignoring defintion from dylib %s",
- proxy.name(), proxy.file()->path(), dylib.file()->path());
+ proxy.name(), proxy.safeFilePath(), dylib.safeFilePath());
pickAtom(dylib);
break;
case Options::kCommonsOverriddenByDylibs:
if ( _options.warnCommons() )
warning("replacing common symbol %s from %s with true definition from dylib %s",
- proxy.name(), proxy.file()->path(), dylib.file()->path());
+ proxy.name(), proxy.safeFilePath(), dylib.safeFilePath());
pickAtom(proxy);
break;
case Options::kCommonsConflictsDylibsError:
throwf("common symbol %s from %s conflicts with defintion from dylib %s",
- proxy.name(), proxy.file()->path(), dylib.file()->path());
+ proxy.name(), proxy.safeFilePath(), dylib.safeFilePath());
}
}
} else if ( _atomB.combine() == ld::Atom::combineByName ) {
pickAtomA();
} else {
- throwf("symbol %s exported from both %s and %s\n", _atomA.name(), _atomA.file()->path(), _atomB.file()->path());
+ throwf("symbol %s exported from both %s and %s\n", _atomA.name(), _atomA.safeFilePath(), _atomB.safeFilePath());
}
}
void pickAtom() {
+ //fprintf(stderr, "pickAtom(), a=%p, def=%d, b=%p, def=%d\n", &_atomA, _atomA.definition(), &_atomB, _atomB.definition());
// First, discriminate by definition
switch (_atomA.definition()) {
case ld::Atom::definitionRegular:
pickBetweenRegularAtoms();
break;
case ld::Atom::definitionTentative:
+ if ( _atomB.size() > _atomA.size() ) {
+ warning("tentative definition of '%s' with size %llu from '%s' is being replaced by real definition of smaller size %llu from '%s'",
+ _atomA.name(), _atomB.size(), _atomB.safeFilePath(), _atomA.size(), _atomA.safeFilePath());
+ }
pickAtomA();
break;
case ld::Atom::definitionAbsolute:
case ld::Atom::definitionTentative:
switch (_atomB.definition()) {
case ld::Atom::definitionRegular:
+ if ( _atomA.size() > _atomB.size() ) {
+ warning("tentative definition of '%s' with size %llu from '%s' is being replaced by real definition of smaller size %llu from '%s'",
+ _atomA.name(), _atomA.size(),_atomA.safeFilePath(), _atomB.size(), _atomB.safeFilePath());
+ }
pickAtomB();
break;
case ld::Atom::definitionTentative:
void SymbolTable::markCoalescedAway(const ld::Atom* atom)
{
// remove this from list of all atoms used
- //fprintf(stderr, "markCoalescedAway(%p) from %s\n", atom, atom->file()->path());
+ //fprintf(stderr, "markCoalescedAway(%p) from %s\n", atom, atom->safeFilePath());
(const_cast<ld::Atom*>(atom))->setCoalescedAway();
//
}
+void SymbolTable::mustPreserveForBitcode(std::unordered_set<const char*>& syms)
+{
+ // return all names in _byNameTable that have no associated atom
+ for (const auto &entry: _byNameTable) {
+ const char* name = entry.first;
+ const ld::Atom* atom = _indirectBindingTable[entry.second];
+ if ( (atom == NULL) || (atom->definition() == ld::Atom::definitionProxy) )
+ syms.insert(name);
+ }
+}
+
+
bool SymbolTable::hasName(const char* name)
{
NameToSlot::iterator pos = _byNameTable.find(name);
return slot;
}
+void SymbolTable::removeDeadAtoms()
+{
+ // remove dead atoms from: _byNameTable, _byNameReverseTable, and _indirectBindingTable
+ std::vector<const char*> namesToRemove;
+ for (NameToSlot::iterator it=_byNameTable.begin(); it != _byNameTable.end(); ++it) {
+ IndirectBindingSlot slot = it->second;
+ const ld::Atom* atom = _indirectBindingTable[slot];
+ if ( atom != NULL ) {
+ if ( !atom->live() && !atom->dontDeadStrip() ) {
+ //fprintf(stderr, "removing from symbolTable[%u] %s\n", slot, atom->name());
+ _indirectBindingTable[slot] = NULL;
+ // <rdar://problem/16025786> need to completely remove dead atoms from symbol table
+ _byNameReverseTable.erase(slot);
+ // can't remove while iterating, do it after iteration
+ namesToRemove.push_back(it->first);
+ }
+ }
+ }
+ for (std::vector<const char*>::iterator it = namesToRemove.begin(); it != namesToRemove.end(); ++it) {
+ _byNameTable.erase(*it);
+ }
+
+ // remove dead atoms from _nonLazyPointerTable
+ for (ReferencesToSlot::iterator it=_nonLazyPointerTable.begin(); it != _nonLazyPointerTable.end(); ) {
+ const ld::Atom* atom = it->first;
+ assert(atom != NULL);
+ if ( !atom->live() && !atom->dontDeadStrip() )
+ it = _nonLazyPointerTable.erase(it);
+ else
+ ++it;
+ }
+
+ // remove dead atoms from _cstringTable
+ for (CStringToSlot::iterator it=_cstringTable.begin(); it != _cstringTable.end(); ) {
+ const ld::Atom* atom = it->first;
+ assert(atom != NULL);
+ if ( !atom->live() && !atom->dontDeadStrip() )
+ it = _cstringTable.erase(it);
+ else
+ ++it;
+ }
+
+ // remove dead atoms from _utf16Table
+ for (UTF16StringToSlot::iterator it=_utf16Table.begin(); it != _utf16Table.end(); ) {
+ const ld::Atom* atom = it->first;
+ assert(atom != NULL);
+ if ( !atom->live() && !atom->dontDeadStrip() )
+ it = _utf16Table.erase(it);
+ else
+ ++it;
+ }
+
+ // remove dead atoms from _cfStringTable
+ for (ReferencesToSlot::iterator it=_cfStringTable.begin(); it != _cfStringTable.end(); ) {
+ const ld::Atom* atom = it->first;
+ assert(atom != NULL);
+ if ( !atom->live() && !atom->dontDeadStrip() )
+ it = _cfStringTable.erase(it);
+ else
+ ++it;
+ }
+
+ // remove dead atoms from _literal4Table
+ for (ContentToSlot::iterator it=_literal4Table.begin(); it != _literal4Table.end(); ) {
+ const ld::Atom* atom = it->first;
+ assert(atom != NULL);
+ if ( !atom->live() && !atom->dontDeadStrip() )
+ it = _literal4Table.erase(it);
+ else
+ ++it;
+ }
+
+ // remove dead atoms from _literal8Table
+ for (ContentToSlot::iterator it=_literal8Table.begin(); it != _literal8Table.end(); ) {
+ const ld::Atom* atom = it->first;
+ assert(atom != NULL);
+ if ( !atom->live() && !atom->dontDeadStrip() )
+ it = _literal8Table.erase(it);
+ else
+ ++it;
+ }
+
+ // remove dead atoms from _literal16Table
+ for (ContentToSlot::iterator it=_literal16Table.begin(); it != _literal16Table.end(); ) {
+ const ld::Atom* atom = it->first;
+ assert(atom != NULL);
+ if ( !atom->live() && !atom->dontDeadStrip() )
+ it = _literal16Table.erase(it);
+ else
+ ++it;
+ }
+}
+
// find existing or create new slot
SymbolTable::IndirectBindingSlot SymbolTable::findSlotForContent(const ld::Atom* atom, const ld::Atom** existingAtom)
slot = _indirectBindingTable.size();
_pointerToCStringTable[atom] = slot;
break;
+ case ld::Section::typeTLVPointers:
+ pos = _threadPointerTable.find(atom);
+ if ( pos != _threadPointerTable.end() ) {
+ *existingAtom = _indirectBindingTable[pos->second];
+ return pos->second;
+ }
+ slot = _indirectBindingTable.size();
+ _threadPointerTable[atom] = slot;
+ break;
default:
assert(0 && "section type does not support coalescing by references");
}
return _indirectBindingTable[slot];
}
+
+void SymbolTable::removeDeadUndefs(std::vector<const ld::Atom*>& allAtoms, const std::unordered_set<const ld::Atom*>& keep)
+{
+ // mark the indirect entries in use
+ std::vector<bool> indirectUsed;
+ for (size_t i=0; i < _indirectBindingTable.size(); ++i)
+ indirectUsed.push_back(false);
+ for (const ld::Atom* atom : allAtoms) {
+ for (auto it = atom->fixupsBegin(); it != atom->fixupsEnd(); ++it) {
+ switch (it->binding) {
+ case ld::Fixup::bindingsIndirectlyBound:
+ indirectUsed[it->u.bindingIndex] = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // any indirect entry not in use which points to an undefined proxy can be removed
+ for (size_t slot=0; slot < indirectUsed.size(); ++slot) {
+ if ( !indirectUsed[slot] ) {
+ const ld::Atom* atom = _indirectBindingTable[slot];
+ if ( (atom != nullptr) && (atom->definition() == ld::Atom::definitionProxy) && (keep.count(atom) == 0) ) {
+ const char* name = atom->name();
+ _indirectBindingTable[slot] = NULL;
+ _byNameReverseTable.erase(slot);
+ _byNameTable.erase(name);
+ allAtoms.erase(std::remove(allAtoms.begin(), allAtoms.end(), atom), allAtoms.end());
+ }
+ }
+ }
+
+}
+
void SymbolTable::printStatistics()
{
// fprintf(stderr, "cstring table size: %lu, bucket count: %lu, hash func called %u times\n",
count[b] = 0;
}
for(unsigned int i=0; i < _cstringTable.bucket_count(); ++i) {
- unsigned int n = _cstringTable.elems_in_bucket(i);
+ unsigned int n = _cstringTable.bucket_size(i);
if ( n < 10 )
count[n] += 1;
else
//ReferencesHash obj;
//for(ReferencesHashToSlot::iterator it=_byReferencesTable.begin(); it != _byReferencesTable.end(); ++it) {
// if ( obj.operator()(it->first) == 0x2F3AC0EAC744EA70 ) {
- // fprintf(stderr, "hash=0x2F3AC0EAC744EA70 for %p %s from %s\n", it->first, it->first->name(), it->first->file()->path());
+ // fprintf(stderr, "hash=0x2F3AC0EAC744EA70 for %p %s from %s\n", it->first, it->first->name(), it->first->safeFilePath());
//
// }
//}