bool SymbolTable::addByName(const Atom &newAtom) { StringRef name = newAtom.name(); assert(!name.empty()); const Atom *existing = findByName(name); if (existing == nullptr) { // Name is not in symbol table yet, add it associate with this atom. _nameTable[name] = &newAtom; return true; } // Do nothing if the same object is added more than once. if (existing == &newAtom) return false; // Name is already in symbol table and associated with another atom. bool useNew = true; switch (collide(existing->definition(), newAtom.definition())) { case NCR_First: useNew = false; break; case NCR_Second: useNew = true; break; case NCR_DupDef: assert(existing->definition() == Atom::definitionRegular); assert(newAtom.definition() == Atom::definitionRegular); switch (mergeSelect(((DefinedAtom*)existing)->merge(), ((DefinedAtom*)&newAtom)->merge())) { case MCR_First: useNew = false; break; case MCR_Second: useNew = true; break; case MCR_Largest: { uint64_t existingSize = sectionSize((DefinedAtom*)existing); uint64_t newSize = sectionSize((DefinedAtom*)&newAtom); useNew = (newSize >= existingSize); break; } case MCR_SameSize: { uint64_t existingSize = sectionSize((DefinedAtom*)existing); uint64_t newSize = sectionSize((DefinedAtom*)&newAtom); if (existingSize == newSize) { useNew = true; break; } llvm::errs() << "Size mismatch: " << existing->name() << " (" << existingSize << ") " << newAtom.name() << " (" << newSize << ")\n"; // fallthrough } case MCR_Error: if (!_context.getAllowDuplicates()) { llvm::errs() << "Duplicate symbols: " << existing->name() << ":" << existing->file().path() << " and " << newAtom.name() << ":" << newAtom.file().path() << "\n"; llvm::report_fatal_error("duplicate symbol error"); } useNew = false; break; } break; case NCR_DupUndef: { const UndefinedAtom* existingUndef = cast<UndefinedAtom>(existing); const UndefinedAtom* newUndef = cast<UndefinedAtom>(&newAtom); bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull()); if (!sameCanBeNull && _context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) { llvm::errs() << "lld warning: undefined symbol " << existingUndef->name() << " has different weakness in " << existingUndef->file().path() << " and in " << newUndef->file().path() << "\n"; } const UndefinedAtom *existingFallback = existingUndef->fallback(); const UndefinedAtom *newFallback = newUndef->fallback(); bool hasDifferentFallback = (existingFallback && newFallback && existingFallback->name() != newFallback->name()); if (hasDifferentFallback) { llvm::errs() << "lld warning: undefined symbol " << existingUndef->name() << " has different fallback: " << existingFallback->name() << " in " << existingUndef->file().path() << " and " << newFallback->name() << " in " << newUndef->file().path() << "\n"; } bool hasNewFallback = newUndef->fallback(); if (sameCanBeNull) useNew = hasNewFallback; else useNew = (newUndef->canBeNull() < existingUndef->canBeNull()); break; } case NCR_DupShLib: { const SharedLibraryAtom *curShLib = cast<SharedLibraryAtom>(existing); const SharedLibraryAtom *newShLib = cast<SharedLibraryAtom>(&newAtom); bool sameNullness = (curShLib->canBeNullAtRuntime() == newShLib->canBeNullAtRuntime()); bool sameName = curShLib->loadName().equals(newShLib->loadName()); if (sameName && !sameNullness && _context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) { // FIXME: need diagonstics interface for writing warning messages llvm::errs() << "lld warning: shared library symbol " << curShLib->name() << " has different weakness in " << curShLib->file().path() << " and in " << newShLib->file().path(); } if (!sameName && _context.warnIfCoalesableAtomsHaveDifferentLoadName()) { // FIXME: need diagonstics interface for writing warning messages llvm::errs() << "lld warning: shared library symbol " << curShLib->name() << " has different load path in " << curShLib->file().path() << " and in " << newShLib->file().path(); } useNew = false; break; } case NCR_Error: llvm::errs() << "SymbolTable: error while merging " << name << "\n"; llvm::report_fatal_error("duplicate symbol error"); break; } if (useNew) { // Update name table to use new atom. _nameTable[name] = &newAtom; // Add existing atom to replacement table. _replacedAtoms[existing] = &newAtom; } else { // New atom is not being used. Add it to replacement table. _replacedAtoms[&newAtom] = existing; } return false; }
void SymbolTable::addByName(const Atom & newAtom) { StringRef name = newAtom.name(); const Atom *existing = this->findByName(name); if (existing == nullptr) { // Name is not in symbol table yet, add it associate with this atom. _nameTable[name] = &newAtom; } else { // Name is already in symbol table and associated with another atom. bool useNew = true; switch (collide(existing->definition(), newAtom.definition())) { case NCR_First: useNew = false; break; case NCR_Second: useNew = true; break; case NCR_DupDef: assert(existing->definition() == Atom::definitionRegular); assert(newAtom.definition() == Atom::definitionRegular); switch ( mergeSelect(((DefinedAtom*)existing)->merge(), ((DefinedAtom*)(&newAtom))->merge()) ) { case MCR_First: useNew = false; break; case MCR_Second: useNew = true; break; case MCR_Largest: useNew = true; break; case MCR_Error: llvm::errs() << "Duplicate symbols: " << existing->name() << ":" << existing->file().path() << " and " << newAtom.name() << ":" << newAtom.file().path() << "\n"; llvm::report_fatal_error("duplicate symbol error"); break; } break; case NCR_DupUndef: { const UndefinedAtom* existingUndef = dyn_cast<UndefinedAtom>(existing); const UndefinedAtom* newUndef = dyn_cast<UndefinedAtom>(&newAtom); assert(existingUndef != nullptr); assert(newUndef != nullptr); if ( existingUndef->canBeNull() == newUndef->canBeNull() ) { useNew = false; } else { if ( _options.warnIfCoalesableAtomsHaveDifferentCanBeNull() ) { // FIXME: need diagonstics interface for writing warning messages llvm::errs() << "lld warning: undefined symbol " << existingUndef->name() << " has different weakness in " << existingUndef->file().path() << " and in " << newUndef->file().path(); } useNew = (newUndef->canBeNull() < existingUndef->canBeNull()); } } break; case NCR_DupShLib: { const SharedLibraryAtom* curShLib = dyn_cast<SharedLibraryAtom>(existing); const SharedLibraryAtom* newShLib = dyn_cast<SharedLibraryAtom>(&newAtom); assert(curShLib != nullptr); assert(newShLib != nullptr); bool sameNullness = (curShLib->canBeNullAtRuntime() == newShLib->canBeNullAtRuntime()); bool sameName = curShLib->loadName().equals(newShLib->loadName()); if ( !sameName ) { useNew = false; if ( _options.warnIfCoalesableAtomsHaveDifferentLoadName() ) { // FIXME: need diagonstics interface for writing warning messages llvm::errs() << "lld warning: shared library symbol " << curShLib->name() << " has different load path in " << curShLib->file().path() << " and in " << newShLib->file().path(); } } else if ( ! sameNullness ) { useNew = false; if ( _options.warnIfCoalesableAtomsHaveDifferentCanBeNull() ) { // FIXME: need diagonstics interface for writing warning messages llvm::errs() << "lld warning: shared library symbol " << curShLib->name() << " has different weakness in " << curShLib->file().path() << " and in " << newShLib->file().path(); } } else { // Both shlib atoms are identical and can be coalesced. useNew = false; } } break; default: llvm::report_fatal_error("SymbolTable::addByName(): unhandled switch clause"); } if ( useNew ) { // Update name table to use new atom. _nameTable[name] = &newAtom; // Add existing atom to replacement table. _replacedAtoms[existing] = &newAtom; } else { // New atom is not being used. Add it to replacement table. _replacedAtoms[&newAtom] = existing; } } }
bool SymbolTable::addByName(const Atom &newAtom) { StringRef name = newAtom.name(); assert(!name.empty()); const Atom *existing = findByName(name); if (existing == nullptr) { // Name is not in symbol table yet, add it associate with this atom. _nameTable[name] = &newAtom; return true; } // Do nothing if the same object is added more than once. if (existing == &newAtom) return false; // Name is already in symbol table and associated with another atom. bool useNew = true; switch (collide(existing->definition(), newAtom.definition())) { case NCR_First: useNew = false; break; case NCR_Second: useNew = true; break; case NCR_DupDef: { const auto *existingDef = cast<DefinedAtom>(existing); const auto *newDef = cast<DefinedAtom>(&newAtom); switch (mergeSelect(existingDef->merge(), newDef->merge())) { case MCR_First: useNew = false; break; case MCR_Second: useNew = true; break; case MCR_Largest: { uint64_t existingSize = existingDef->sectionSize(); uint64_t newSize = newDef->sectionSize(); useNew = (newSize >= existingSize); break; } case MCR_SameSize: { uint64_t existingSize = existingDef->sectionSize(); uint64_t newSize = newDef->sectionSize(); if (existingSize == newSize) { useNew = true; break; } llvm::errs() << "Size mismatch: " << existing->name() << " (" << existingSize << ") " << newAtom.name() << " (" << newSize << ")\n"; LLVM_FALLTHROUGH; } case MCR_Error: llvm::errs() << "Duplicate symbols: " << existing->name() << ":" << existing->file().path() << " and " << newAtom.name() << ":" << newAtom.file().path() << "\n"; llvm::report_fatal_error("duplicate symbol error"); break; } break; } case NCR_DupUndef: { const UndefinedAtom* existingUndef = cast<UndefinedAtom>(existing); const UndefinedAtom* newUndef = cast<UndefinedAtom>(&newAtom); bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull()); if (sameCanBeNull) useNew = false; else useNew = (newUndef->canBeNull() < existingUndef->canBeNull()); break; } case NCR_DupShLib: { useNew = false; break; } case NCR_Error: llvm::errs() << "SymbolTable: error while merging " << name << "\n"; llvm::report_fatal_error("duplicate symbol error"); break; } if (useNew) { // Update name table to use new atom. _nameTable[name] = &newAtom; // Add existing atom to replacement table. _replacedAtoms[existing] = &newAtom; } else { // New atom is not being used. Add it to replacement table. _replacedAtoms[&newAtom] = existing; } return false; }