- bool useNew = true;
- bool checkVisibilityMismatch = false;
- assert(newAtom.name() != NULL);
- const char* name = newAtom.name();
- IndirectBindingSlot slot = this->findSlotForName(name);
- const ld::Atom* existingAtom = _indirectBindingTable[slot];
- //fprintf(stderr, "addByName(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
- if ( existingAtom != NULL ) {
- assert(&newAtom != existingAtom);
- switch ( existingAtom->definition() ) {
- case ld::Atom::definitionRegular:
- switch ( newAtom.definition() ) {
- case ld::Atom::definitionRegular:
- if ( existingAtom->combine() == ld::Atom::combineByName ) {
- if ( newAtom.combine() == ld::Atom::combineByName ) {
- // <rdar://problem/9183821> always choose mach-o over llvm bit code, otherwise LTO may eliminate the llvm atom
- const bool existingIsLTO = (existingAtom->contentType() == ld::Atom::typeLTOtemporary);
- const bool newIsLTO = (newAtom.contentType() == ld::Atom::typeLTOtemporary);
- if ( existingIsLTO != newIsLTO ) {
- useNew = existingIsLTO;
- }
- else {
- // both weak, prefer non-auto-hide one
- if ( newAtom.autoHide() != existingAtom->autoHide() ) {
- // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
- useNew = existingAtom->autoHide();
- // don't check for visibility mismatch
- }
- else if ( newAtom.autoHide() && existingAtom->autoHide() ) {
- // both have auto-hide, so use one with greater alignment
- useNew = ( newAtom.alignment().trailingZeros() > existingAtom->alignment().trailingZeros() );
- }
- else {
- // neither auto-hide, check visibility
- if ( newAtom.scope() != existingAtom->scope() ) {
- // <rdar://problem/8304984> use more visible weak def symbol
- useNew = (newAtom.scope() == ld::Atom::scopeGlobal);
- }
- else {
- // both have same visibility, use one with greater alignment
- useNew = ( newAtom.alignment().trailingZeros() > existingAtom->alignment().trailingZeros() );
- }
- }
- }
- }
- else {
- // existing weak, new is not-weak
- useNew = true;
- }
+ bool foundDuplicate = false;
+ for (DuplicateSymbols::const_iterator symbolIt = _duplicateSymbols.begin(); symbolIt != _duplicateSymbols.end(); symbolIt++) {
+ DuplicatedSymbolAtomList *atoms = symbolIt->second;
+ bool reportDuplicate;
+ if (_options.deadCodeStrip()) {
+ // search for a live atom
+ reportDuplicate = false;
+ for (DuplicatedSymbolAtomList::iterator it = atoms->begin(); !reportDuplicate && it != atoms->end(); it++) {
+ if ((*it)->live())
+ reportDuplicate = true;
+ }
+ } else {
+ reportDuplicate = true;
+ }
+ if (reportDuplicate) {
+ 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());
+ }
+ }
+ }
+ if (foundDuplicate)
+ throwf("%d duplicate symbol%s", (int)_duplicateSymbols.size(), _duplicateSymbols.size()==1?"":"s");
+}
+
+// AtomPicker encapsulates the logic for picking which atom to use when adding an atom by name results in a collision
+class NameCollisionResolution {
+public:
+ NameCollisionResolution(const ld::Atom& a, const ld::Atom& b, bool ignoreDuplicates, const Options& options) : _atomA(a), _atomB(b), _options(options), _reportDuplicate(false), _ignoreDuplicates(ignoreDuplicates) {
+ pickAtom();
+ }
+
+ // Returns which atom to use
+ const ld::Atom& chosen() { return *_chosen; }
+ bool choseAtom(const ld::Atom& atom) { return _chosen == &atom; }
+
+ // Returns true if the two atoms should be reported as a duplicate symbol
+ bool reportDuplicate() { return _reportDuplicate; }
+
+private:
+ const ld::Atom& _atomA;
+ const ld::Atom& _atomB;
+ const Options& _options;
+ const ld::Atom* _chosen;
+ bool _reportDuplicate;
+ bool _ignoreDuplicates;
+
+ void pickAtom(const ld::Atom& atom) { _chosen = &atom; } // primitive to set which atom is picked
+ void pickAtomA() { pickAtom(_atomA); } // primitive to pick atom A
+ void pickAtomB() { pickAtom(_atomB); } // primitive to pick atom B
+
+ // use atom A if pickA, otherwise use atom B
+ void pickAOrB(bool pickA) { if (pickA) pickAtomA(); else pickAtomB(); }
+
+ void pickHigherOrdinal() {
+ pickAOrB(_atomA.file()->ordinal() < _atomB.file()->ordinal());
+ }
+
+ void pickLowerOrdinal() {
+ pickAOrB(_atomA.file()->ordinal() > _atomB.file()->ordinal());
+ }
+
+ void pickLargerSize() {
+ if (_atomA.size() == _atomB.size())
+ pickLowerOrdinal();
+ else
+ pickAOrB(_atomA.size() > _atomB.size());
+ }
+
+ void pickGreaterAlignment() {
+ pickAOrB(_atomA.alignment().trailingZeros() > _atomB.alignment().trailingZeros());
+ }
+
+ void pickBetweenRegularAtoms() {
+ if ( _atomA.combine() == ld::Atom::combineByName ) {
+ if ( _atomB.combine() == ld::Atom::combineByName ) {
+ // <rdar://problem/9183821> always choose mach-o over llvm bit code, otherwise LTO may eliminate the llvm atom
+ const bool aIsLTO = (_atomA.contentType() == ld::Atom::typeLTOtemporary);
+ const bool bIsLTO = (_atomB.contentType() == ld::Atom::typeLTOtemporary);
+ // <rdar://problem/9183821> always choose mach-o over llvm bit code, otherwise LTO may eliminate the llvm atom
+ if ( aIsLTO != bIsLTO ) {
+ pickAOrB(!aIsLTO);
+ }
+ else {
+ // both weak, prefer non-auto-hide one
+ if ( _atomA.autoHide() != _atomB.autoHide() ) {
+ // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
+ pickAOrB(!_atomA.autoHide());
+ }
+ else if ( _atomA.autoHide() && _atomB.autoHide() ) {
+ // both have auto-hide, so use one with greater alignment
+ pickGreaterAlignment();
+ }
+ else {
+ // neither auto-hide, check visibility
+ if ( _atomA.scope() != _atomB.scope() ) {
+ // <rdar://problem/8304984> use more visible weak def symbol
+ pickAOrB(_atomA.scope() == ld::Atom::scopeGlobal);