]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/SymbolTable.cpp
ld64-409.12.tar.gz
[apple/ld64.git] / src / ld / SymbolTable.cpp
index 406556a501dc902c79162d2b540fc2849c7ad380..e12c1e4460e7478fcae0417cb0e7929188b91d2d 100644 (file)
@@ -41,8 +41,6 @@
 #include <set>
 #include <vector>
 #include <algorithm>
-#include <ext/hash_map>
-#include <ext/hash_set>
 
 #include "Options.h"
 
@@ -134,7 +132,7 @@ void SymbolTable::addDuplicateSymbol(const char *name, const ld::Atom *atom)
     // 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);
@@ -160,7 +158,7 @@ void SymbolTable::checkDuplicateSymbols() const
             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());
             }
         }
     }
@@ -286,18 +284,18 @@ private:
                        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());
                }
        }
        
@@ -309,11 +307,12 @@ private:
                } 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:
@@ -322,6 +321,10 @@ private:
                                                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:
@@ -336,6 +339,10 @@ private:
                        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:
@@ -494,7 +501,7 @@ bool SymbolTable::add(const ld::Atom& atom, bool ignoreDuplicates)
 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();
        
        //
@@ -555,6 +562,18 @@ void SymbolTable::tentativeDefs(std::vector<const char*>& tents)
 }
 
 
+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);
@@ -577,6 +596,99 @@ SymbolTable::IndirectBindingSlot SymbolTable::findSlotForName(const char* 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)
@@ -709,6 +821,15 @@ SymbolTable::IndirectBindingSlot SymbolTable::findSlotForReferences(const ld::At
                        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");
        }
@@ -739,6 +860,41 @@ const ld::Atom* SymbolTable::indirectAtom(IndirectBindingSlot slot) const
        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", 
@@ -748,7 +904,7 @@ void SymbolTable::printStatistics()
                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
@@ -768,7 +924,7 @@ void SymbolTable::printStatistics()
        //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());
        //      
        //      }
        //}