Index: llvm/include/llvm/MC/MCWinEH.h =================================================================== --- llvm/include/llvm/MC/MCWinEH.h +++ llvm/include/llvm/MC/MCWinEH.h @@ -53,6 +53,15 @@ const FrameInfo *ChainedParent) : Begin(BeginFuncEHLabel), Function(Function), ChainedParent(ChainedParent) {} + + bool empty() const { + if (!Instructions.empty()) + return false; + for (const auto &E : EpilogMap) + if (!E.second.empty()) + return false; + return true; + } }; class UnwindEmitter { Index: llvm/lib/MC/MCWin64EH.cpp =================================================================== --- llvm/lib/MC/MCWin64EH.cpp +++ llvm/lib/MC/MCWin64EH.cpp @@ -576,7 +576,13 @@ if (CodeWordsMod) CodeWords++; uint32_t EpilogCount = info->EpilogMap.size(); - bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124; + // If we need to signal a larger EpilogCount or TotalCodeBytes, we need to + // use the extension word, and leave those fields as zero in row1. + // If both EpilogCount and CodeWords actually are zero though (e.g. due to + // missing/incomplete .seh directives in assembly), we still need to include + // the extension word, as that is how the reader will interpret it. + bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124 || + (EpilogCount == 0 && CodeWords == 0); if (!ExtensionWord) { row1 |= (EpilogCount & 0x1F) << 22; row1 |= (CodeWords & 0x1F) << 27; @@ -657,16 +663,25 @@ void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const { // Emit the unwind info structs first. for (const auto &CFI : Streamer.getWinFrameInfos()) { + WinEH::FrameInfo *Info = CFI.get(); + if (Info->empty()) + continue; MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection); Streamer.SwitchSection(XData); - ARM64EmitUnwindInfo(Streamer, CFI.get()); + ARM64EmitUnwindInfo(Streamer, Info); } // Now emit RUNTIME_FUNCTION entries. for (const auto &CFI : Streamer.getWinFrameInfos()) { + WinEH::FrameInfo *Info = CFI.get(); + // ARM64EmitUnwindInfo above clears the info struct, so we can't check + // empty here. But if a Symbol is set, we should create the corresponding + // pdata entry. + if (!Info->Symbol) + continue; MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection); Streamer.SwitchSection(PData); - ARM64EmitRuntimeFunction(Streamer, CFI.get()); + ARM64EmitRuntimeFunction(Streamer, Info); } } Index: llvm/test/MC/AArch64/seh.s =================================================================== --- llvm/test/MC/AArch64/seh.s +++ llvm/test/MC/AArch64/seh.s @@ -1,6 +1,8 @@ // This test checks that the SEH directives don't cause the assembler to fail. +// Checking that llvm-readobj doesn't bail out on the unwind data, but not +// really checking the contents yet. -// RUN: llvm-mc -triple aarch64-pc-win32 -filetype=obj %s | llvm-readobj -S -r - | FileCheck %s +// RUN: llvm-mc -triple aarch64-pc-win32 -filetype=obj %s | llvm-readobj -S -r -u - | FileCheck %s // CHECK: Sections [ // CHECK: Section { @@ -15,8 +17,8 @@ // CHECK-NEXT: } // CHECK: Section { // CHECK: Name: .xdata -// CHECK: RawDataSize: 20 -// CHECK: RelocationCount: 1 +// CHECK: RawDataSize: 32 +// CHECK: RelocationCount: 2 // CHECK: Characteristics [ // CHECK-NEXT: ALIGN_4BYTES // CHECK-NEXT: CNT_INITIALIZED_DATA @@ -37,11 +39,12 @@ // CHECK-NEXT: Relocations [ // CHECK-NEXT: Section (4) .xdata { // CHECK-NEXT: 0x8 IMAGE_REL_ARM64_ADDR32NB __C_specific_handler +// CHECK-NEXT: 0x18 IMAGE_REL_ARM64_ADDR32NB __C_specific_handler // CHECK-NEXT: } // CHECK-NEXT: Section (5) .pdata { // CHECK-NEXT: 0x0 IMAGE_REL_ARM64_ADDR32NB func // CHECK-NEXT: 0x4 IMAGE_REL_ARM64_ADDR32NB .xdata -// CHECK-NEXT: 0x8 IMAGE_REL_ARM64_ADDR32NB smallFunc +// CHECK-NEXT: 0x8 IMAGE_REL_ARM64_ADDR32NB handlerFunc // CHECK-NEXT: 0xC IMAGE_REL_ARM64_ADDR32NB .xdata // CHECK-NEXT: } // CHECK-NEXT: ] @@ -67,7 +70,8 @@ ret .seh_endproc -// Test emission of small functions. + // Function with no .seh directives; no pdata/xdata entries are + // generated. .globl smallFunc .def smallFunc .scl 2 @@ -77,3 +81,19 @@ smallFunc: ret .seh_endproc + + // Function with no .seh directives, but with .seh_handlerdata, which + // forces generating the xdata/pdata entries. + .globl handlerFunc + .def handlerFunc + .scl 2 + .type 32 + .endef + .seh_proc handlerFunc +handlerFunc: + ret + .seh_handler __C_specific_handler, @except + .seh_handlerdata + .long 0 + .text + .seh_endproc