Index: lld/trunk/COFF/ICF.cpp =================================================================== --- lld/trunk/COFF/ICF.cpp +++ lld/trunk/COFF/ICF.cpp @@ -73,12 +73,23 @@ // 2017) says that /opt:icf folds both functions and read-only data. // Despite that, the MSVC linker folds only functions. We found // a few instances of programs that are not safe for data merging. -// Therefore, we merge only functions just like the MSVC tool. +// Therefore, we merge only functions just like the MSVC tool. However, we merge +// identical .xdata sections, because the address of unwind information is +// insignificant to the user program and the Visual C++ linker does this. bool ICF::isEligible(SectionChunk *C) { + // Non-comdat chunks, dead chunks, and writable chunks are not elegible. + bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE; + if (!C->isCOMDAT() || !C->isLive() || Writable) + return false; + + // Code sections with external symbols are eligible. bool Global = C->Sym && C->Sym->isExternal(); bool Executable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE; - bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE; - return C->isCOMDAT() && C->isLive() && Global && Executable && !Writable; + if (Global && Executable) + return true; + + // .xdata unwind info sections are eligble. + return C->getSectionName().split('$').first == ".xdata"; } // Split an equivalence class into smaller classes. Index: lld/trunk/test/COFF/icf-xdata.s =================================================================== --- lld/trunk/test/COFF/icf-xdata.s +++ lld/trunk/test/COFF/icf-xdata.s @@ -0,0 +1,86 @@ +# RUN: llvm-mc %s -triple x86_64-windows-msvc -filetype=obj -o %t.obj +# RUN: lld-link %t.obj -dll -noentry -out:%t.dll +# RUN: llvm-readobj -sections %t.dll | FileCheck %s + +# There shouldn't be much xdata, because all three .pdata entries (12 bytes +# each) should use the same .xdata unwind info. +# CHECK: Name: .pdata +# CHECK-NEXT: VirtualSize: 0x24 +# CHECK: Name: .xdata +# CHECK-NEXT: VirtualSize: 0x8 + + .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 + .def xdata2; + .scl 2; + .type 32; + .endef + .section .text,"xr",one_only,xdata2 + .globl xdata2 # -- Begin function xdata2 + .p2align 4, 0x90 +xdata2: # @xdata2 +.seh_proc xdata2 +# BB#0: # %entry + subq $40, %rsp + .seh_stackalloc 40 + .seh_endprologue + callq callee + callq callee + nop + addq $40, %rsp + jmp callee # TAILCALL + .seh_handlerdata + .section .text,"xr",one_only,xdata2 + .seh_endproc + # -- End function + .def xdata3; + .scl 2; + .type 32; + .endef + .section .text,"xr",one_only,xdata3 + .globl xdata3 # -- Begin function xdata3 + .p2align 4, 0x90 +xdata3: # @xdata3 +.seh_proc xdata3 +# BB#0: # %entry + subq $40, %rsp + .seh_stackalloc 40 + .seh_endprologue + callq callee + callq callee + callq callee + nop + addq $40, %rsp + jmp callee # TAILCALL + .seh_handlerdata + .section .text,"xr",one_only,xdata3 + .seh_endproc + # -- End function + .section .drectve,"yn" + .ascii " -export:xdata1" + .ascii " -export:xdata2" + .ascii " -export:xdata3" +