diff options
Diffstat (limited to 'lld')
| -rw-r--r-- | lld/include/lld/Core/DefinedAtom.h | 1 | ||||
| -rw-r--r-- | lld/lib/Core/SymbolTable.cpp | 59 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp | 4 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp | 1 | ||||
| -rw-r--r-- | lld/test/pecoff/Inputs/merge-largest1.obj.yaml | 25 | ||||
| -rw-r--r-- | lld/test/pecoff/Inputs/merge-largest2.obj.yaml | 25 | ||||
| -rw-r--r-- | lld/test/pecoff/merge-largest.test | 24 | 
7 files changed, 124 insertions, 15 deletions
| diff --git a/lld/include/lld/Core/DefinedAtom.h b/lld/include/lld/Core/DefinedAtom.h index fb7c44aa121..1f4e95111b9 100644 --- a/lld/include/lld/Core/DefinedAtom.h +++ b/lld/include/lld/Core/DefinedAtom.h @@ -99,6 +99,7 @@ public:      mergeAsWeakAndAddressUsed, // Is C++ definition inline definition whose                                 // address was taken.      mergeSameNameAndSize,   // Another atom with different size is error +    mergeByLargestSection,  // Choose an atom whose section is the largest.      mergeByContent,         // Merge with other constants with same content.    }; diff --git a/lld/lib/Core/SymbolTable.cpp b/lld/lib/Core/SymbolTable.cpp index add6628096e..9bacdad17d9 100644 --- a/lld/lib/Core/SymbolTable.cpp +++ b/lld/lib/Core/SymbolTable.cpp @@ -102,13 +102,14 @@ enum MergeResolution {    MCR_Error  }; -static MergeResolution mergeCases[][5] = { -  // no          tentative      weak          weakAddress   sameNameAndSize -  {MCR_Error,    MCR_First,     MCR_First,    MCR_First,    MCR_SameSize}, // no -  {MCR_Second,   MCR_Largest,   MCR_Second,   MCR_Second,   MCR_SameSize}, // tentative -  {MCR_Second,   MCR_First,     MCR_First,    MCR_Second,   MCR_SameSize}, // weak -  {MCR_Second,   MCR_First,     MCR_First,    MCR_First,    MCR_SameSize}, // weakAddress -  {MCR_SameSize, MCR_SameSize,  MCR_SameSize, MCR_SameSize, MCR_SameSize}, // sameSize +static MergeResolution mergeCases[][6] = { +  // no          tentative      weak          weakAddress   sameNameAndSize largest +  {MCR_Error,    MCR_First,     MCR_First,    MCR_First,    MCR_SameSize,   MCR_Largest},  // no +  {MCR_Second,   MCR_Largest,   MCR_Second,   MCR_Second,   MCR_SameSize,   MCR_Largest},  // tentative +  {MCR_Second,   MCR_First,     MCR_First,    MCR_Second,   MCR_SameSize,   MCR_Largest},  // weak +  {MCR_Second,   MCR_First,     MCR_First,    MCR_First,    MCR_SameSize,   MCR_Largest},  // weakAddress +  {MCR_SameSize, MCR_SameSize,  MCR_SameSize, MCR_SameSize, MCR_SameSize,   MCR_SameSize}, // sameSize +  {MCR_Largest,  MCR_Largest,   MCR_Largest,  MCR_Largest,  MCR_SameSize,   MCR_Largest},  // largest  };  static MergeResolution mergeSelect(DefinedAtom::Merge first, @@ -118,6 +119,33 @@ static MergeResolution mergeSelect(DefinedAtom::Merge first,    return mergeCases[first][second];  } +static uint64_t getSizeFollowReferences(const DefinedAtom *atom, uint32_t kind) { +  uint64_t size = 0; +redo: +  while (atom) { +    for (const Reference *r : *atom) { +      if (r->kindNamespace() == Reference::KindNamespace::all && +          r->kindArch() == Reference::KindArch::all && +          r->kindValue() == kind) { +        atom = cast<DefinedAtom>(r->target()); +        size += atom->size(); +        goto redo; +      } +    } +    break; +  } +  return size; +} + +// Returns the size of the section containing the given atom. Atoms in the same +// section are connected by layout-before and layout-after edges, so this +// function traverses them to get the total size of atoms in the same section. +static uint64_t sectionSize(const DefinedAtom *atom) { +  return atom->size() +      + getSizeFollowReferences(atom, lld::Reference::kindLayoutBefore) +      + getSizeFollowReferences(atom, lld::Reference::kindLayoutAfter); +} +  void SymbolTable::addByName(const Atom &newAtom) {    StringRef name = newAtom.name();    assert(!name.empty()); @@ -148,19 +176,22 @@ void SymbolTable::addByName(const Atom &newAtom) {      case MCR_Second:        useNew = true;        break; -    case MCR_Largest: -      useNew = true; +    case MCR_Largest: { +      uint64_t existingSize = sectionSize((DefinedAtom*)existing); +      uint64_t newSize = sectionSize((DefinedAtom*)&newAtom); +      useNew = (newSize >= existingSize);        break; +    }      case MCR_SameSize: { -      uint64_t sa = ((DefinedAtom*)existing)->size(); -      uint64_t sb = ((DefinedAtom*)&newAtom)->size(); -      if (sa == sb) { +      uint64_t existingSize = sectionSize((DefinedAtom*)existing); +      uint64_t newSize = sectionSize((DefinedAtom*)&newAtom); +      if (existingSize == newSize) {          useNew = true;          break;        }        llvm::errs() << "Size mismatch: " -                   << existing->name() << " (" << sa << ") " -                   << newAtom.name() << " (" << sb << ")\n"; +                   << existing->name() << " (" << existingSize << ") " +                   << newAtom.name() << " (" << newSize << ")\n";        // fallthrough      }      case MCR_Error: diff --git a/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp index b5f0de049d5..c32ca9762d9 100644 --- a/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp +++ b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp @@ -250,11 +250,13 @@ DefinedAtom::Merge getMerge(const coff_aux_section_definition *auxsym) {    case llvm::COFF::IMAGE_COMDAT_SELECT_ANY:      return DefinedAtom::mergeAsWeakAndAddressUsed;    case llvm::COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH: +    // TODO: This mapping is wrong. Fix it.      return DefinedAtom::mergeByContent;    case llvm::COFF::IMAGE_COMDAT_SELECT_SAME_SIZE:      return DefinedAtom::mergeSameNameAndSize; -  case llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE:    case llvm::COFF::IMAGE_COMDAT_SELECT_LARGEST: +    return DefinedAtom::mergeByLargestSection; +  case llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE:    case llvm::COFF::IMAGE_COMDAT_SELECT_NEWEST:      // FIXME: These attributes has more complicated semantics than the regular      // weak symbol. These are mapped to mergeAsWeakAndAddressUsed for now diff --git a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp index fe3cffdafe4..e4c809f11d2 100644 --- a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -340,6 +340,7 @@ template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Merge> {      io.enumCase(value, "by-content",   lld::DefinedAtom::mergeByContent);      io.enumCase(value, "same-name-and-size",                  lld::DefinedAtom::mergeSameNameAndSize); +    io.enumCase(value, "largest", lld::DefinedAtom::mergeByLargestSection);    }  }; diff --git a/lld/test/pecoff/Inputs/merge-largest1.obj.yaml b/lld/test/pecoff/Inputs/merge-largest1.obj.yaml new file mode 100644 index 00000000000..40ba41f3672 --- /dev/null +++ b/lld/test/pecoff/Inputs/merge-largest1.obj.yaml @@ -0,0 +1,25 @@ +--- +header: +  Machine:         IMAGE_FILE_MACHINE_I386 +  Characteristics: [  ] +sections: +  - Name:            .text +    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] +    Alignment:       16 +    SectionData:     00112233 +symbols: +  - Name:            .text +    Value:           0 +    SectionNumber:   1 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_NULL +    StorageClass:    IMAGE_SYM_CLASS_STATIC +    NumberOfAuxSymbols: 1 +    AuxiliaryData:   0700000000000000C979F796000006000000 +  - Name:            "_foo" +    Value:           0 +    SectionNumber:   1 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION +    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/lld/test/pecoff/Inputs/merge-largest2.obj.yaml b/lld/test/pecoff/Inputs/merge-largest2.obj.yaml new file mode 100644 index 00000000000..962489a20a1 --- /dev/null +++ b/lld/test/pecoff/Inputs/merge-largest2.obj.yaml @@ -0,0 +1,25 @@ +--- +header: +  Machine:         IMAGE_FILE_MACHINE_I386 +  Characteristics: [  ] +sections: +  - Name:            .text +    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] +    Alignment:       16 +    SectionData:     0011223344556677 +symbols: +  - Name:            .text +    Value:           0 +    SectionNumber:   1 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_NULL +    StorageClass:    IMAGE_SYM_CLASS_STATIC +    NumberOfAuxSymbols: 1 +    AuxiliaryData:   0700000000000000C979F796000006000000 +  - Name:            "_foo" +    Value:           6 +    SectionNumber:   1 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION +    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/lld/test/pecoff/merge-largest.test b/lld/test/pecoff/merge-largest.test new file mode 100644 index 00000000000..73d2d940660 --- /dev/null +++ b/lld/test/pecoff/merge-largest.test @@ -0,0 +1,24 @@ +# RUN: yaml2obj %p/Inputs/merge-largest1.obj.yaml > %t1.obj +# RUN: yaml2obj %p/Inputs/merge-largest2.obj.yaml > %t2.obj +# +# RUN: lld -flavor link /out:%t.exe /subsystem:console /opt:noref /force \ +# RUN:   -- %t1.obj %t2.obj 2>&1 > %t.log +# +# FileCheck complains if the input files is empty, so add a dummy line. +# RUN: echo foo >> %t.log +# RUN: FileCheck -check-prefix=STDERR %s < %t.log +# +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=READOBJ %s + +STDERR-NOT: duplicate symbol error + +READOBJ:      Format: COFF-i386 +READOBJ-NEXT: Arch: i386 +READOBJ-NEXT: AddressSize: 32bit +READOBJ-NEXT: Sections [ +READOBJ-NEXT:   Section { +READOBJ-NEXT:     Number: 1 +READOBJ-NEXT:     Name: .text (2E 74 65 78 74 00 00 00) +READOBJ-NEXT:     VirtualSize: 0x8 +READOBJ-NEXT:     VirtualAddress: 0x1000 +READOBJ-NEXT:     RawDataSize: 8 | 

