Index: lld/COFF/Chunks.h =================================================================== --- lld/COFF/Chunks.h +++ lld/COFF/Chunks.h @@ -217,6 +217,11 @@ ArrayRef Relocs; + // The associative .pdata section if this is a COMDAT chunk. + // A section and its associative .pdata must be ICFed as a unit. + // This field makes it convenient to access the .pdata during ICF. + SectionChunk *Pdata = nullptr; + private: StringRef SectionName; std::vector AssocChildren; Index: lld/COFF/Chunks.cpp =================================================================== --- lld/COFF/Chunks.cpp +++ lld/COFF/Chunks.cpp @@ -363,6 +363,8 @@ void SectionChunk::addAssociative(SectionChunk *Child) { AssocChildren.push_back(Child); + if (Child->getSectionName().split('$').first == ".pdata") + Pdata = Child; } static uint8_t getBaserelType(const coff_relocation &Rel) { @@ -440,6 +442,10 @@ void SectionChunk::replace(SectionChunk *Other) { Other->Repl = Repl; Other->Live = false; + if (Pdata) { + Other->Pdata->Repl = Pdata->Repl; + Other->Pdata->Live = false; + } } CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) { Index: lld/COFF/ICF.cpp =================================================================== --- lld/COFF/ICF.cpp +++ lld/COFF/ICF.cpp @@ -149,7 +149,9 @@ return A->getOutputCharacteristics() == B->getOutputCharacteristics() && A->SectionName == B->SectionName && A->Alignment == B->Alignment && A->Header->SizeOfRawData == B->Header->SizeOfRawData && - A->Checksum == B->Checksum && A->getContents() == B->getContents(); + A->Checksum == B->Checksum && A->getContents() == B->getContents() && + (A->Pdata ? (B->Pdata && equalsConstant(A->Pdata, B->Pdata)) + : !B->Pdata); } // Compare "moving" part of two sections, namely relocation targets. @@ -165,7 +167,10 @@ return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2]; return false; }; - return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq); + return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), + Eq) && + (A->Pdata ? (B->Pdata && equalsVariable(A->Pdata, B->Pdata)) + : !B->Pdata); } // Find the first Chunk after Begin that has a different class from Begin. Index: lld/test/COFF/icf-pdata.s =================================================================== --- /dev/null +++ lld/test/COFF/icf-pdata.s @@ -0,0 +1,92 @@ +# RUN: llvm-mc %s -triple x86_64-windows-msvc -filetype=obj -o %t.obj +# RUN: lld-link %t.obj -dll -noentry -out:%t.dll -merge:.xdata=.xdata +# RUN: llvm-readobj -sections -coff-exports %t.dll | FileCheck %s + +# CHECK: Name: .pdata +# CHECK-NEXT: VirtualSize: 0x18 +# CHECK: Name: .xdata +# CHECK-NEXT: VirtualSize: 0x10 + +# CHECK: Name: xdata1 +# CHECK-NEXT: RVA: 0x1010 +# CHECK: Name: xdata1a +# CHECK-NEXT: RVA: 0x1010 +# CHECK: Name: xdata1b +# CHECK-NEXT: RVA: 0x1030 + + .text +callee: + ret + + .def xdata1; + .scl 2; + .type 32; + .endef + .section .text,"xr",one_only,xdata1 + .globl xdata1 # -- Begin function xdata1 + .p2align 4, 0x90 +xdata1: # @xdata1 +.seh_proc xdata1 +# BB#0: # %entry + subq $40, %rsp + .seh_stackalloc 40 + .seh_endprologue + callq callee + nop + addq $40, %rsp + jmp callee # TAILCALL + .seh_handlerdata + .section .text,"xr",one_only,xdata1 + .seh_endproc + # -- End function + +# xdata1a is identical to xdata1, so it should be ICFd, and so should its pdata. + .def xdata1a; + .scl 2; + .type 32; + .endef + .section .text,"xr",one_only,xdata1a + .globl xdata1a # -- Begin function xdata1a + .p2align 4, 0x90 +xdata1a: # @xdata1a +.seh_proc xdata1a +# BB#0: # %entry + subq $40, %rsp + .seh_stackalloc 40 + .seh_endprologue + callq callee + nop + addq $40, %rsp + jmp callee # TAILCALL + .seh_handlerdata + .section .text,"xr",one_only,xdata1a + .seh_endproc + +# xdata1b's text is identical to xdata1, but its xdata specifies a different +# stack size, so it cannot be ICFd with xdata1. + .def xdata1b; + .scl 2; + .type 32; + .endef + .section .text,"xr",one_only,xdata1b + .globl xdata1b # -- Begin function xdata1b + .p2align 4, 0x90 +xdata1b: # @xdata1b +.seh_proc xdata1b +# BB#0: # %entry + subq $40, %rsp + .seh_stackalloc 48 + .seh_endprologue + callq callee + nop + addq $40, %rsp + jmp callee # TAILCALL + .seh_handlerdata + .section .text,"xr",one_only,xdata1b + .seh_endproc + # -- End function + + .section .drectve,"yn" + .ascii " -export:xdata1" + .ascii " -export:xdata1a" + .ascii " -export:xdata1b"