diff --git a/lib/MC/MCWin64EH.cpp b/lib/MC/MCWin64EH.cpp index c3d568b454c..b8b07d3a180 100644 --- a/lib/MC/MCWin64EH.cpp +++ b/lib/MC/MCWin64EH.cpp @@ -159,11 +159,11 @@ static void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) { MCContext &context = streamer.getContext(); streamer.EmitValueToAlignment(4); - // Upper 3 bits are the version number (currently 1). - uint8_t flags = 0x01; info->Symbol = context.CreateTempSymbol(); streamer.EmitLabel(info->Symbol); + // Upper 3 bits are the version number (currently 1). + uint8_t flags = 0x01; if (info->ChainedParent) flags |= Win64EH::UNW_ChainInfo << 3; else { @@ -199,6 +199,14 @@ static void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) { EmitUnwindCode(streamer, info->Begin, inst); } + // For alignment purposes, the instruction array will always have an even + // number of entries, with the final entry potentially unused (in which case + // the array will be one longer than indicated by the count of unwind codes + // field). + if (numCodes & 1) { + streamer.EmitIntValue(0, 2); + } + if (flags & (Win64EH::UNW_ChainInfo << 3)) EmitRuntimeFunction(streamer, info->ChainedParent); else if (flags & @@ -206,14 +214,11 @@ static void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) { streamer.EmitValue(MCSymbolRefExpr::Create(info->ExceptionHandler, MCSymbolRefExpr::VK_COFF_IMGREL32, context), 4); - else if (numCodes < 2) { + else if (numCodes == 0) { // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not // a chained unwind info, if there is no handler, and if there are fewer // than 2 slots used in the unwind code array, we have to pad to 8 bytes. - if (numCodes == 1) - streamer.EmitIntValue(0, 2); - else - streamer.EmitIntValue(0, 4); + streamer.EmitIntValue(0, 4); } } diff --git a/test/MC/COFF/seh-align1.s b/test/MC/COFF/seh-align1.s new file mode 100644 index 00000000000..aafc6ede085 --- /dev/null +++ b/test/MC/COFF/seh-align1.s @@ -0,0 +1,65 @@ +// This test checks the alignment and padding of the unwind info. + +// RUN: llvm-mc -triple x86_64-pc-win32 -filetype=obj %s | llvm-readobj -s -sd -sr -u | FileCheck %s + +// CHECK: Sections [ +// CHECK: Section { +// CHECK: Name: .xdata +// CHECK: RawDataSize: 8 +// CHECK: RelocationCount: 0 +// CHECK: Characteristics [ +// CHECK-NEXT: ALIGN_4BYTES +// CHECK-NEXT: CNT_INITIALIZED_DATA +// CHECK-NEXT: MEM_READ +// CHECK-NEXT: ] +// CHECK: Relocations [ +// CHECK-NEXT: ] +// CHECK: SectionData ( +// CHECK-NEXT: 0000: 01000000 00000000 +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK: Section { +// CHECK: Name: .pdata +// CHECK: RawDataSize: 12 +// CHECK: RelocationCount: 3 +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_4BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: ] +// CHECK: Relocations [ +// CHECK-NEXT: [[BeginDisp:0x[A-F0-9]+]] IMAGE_REL_AMD64_ADDR32NB smallFunc +// CHECK-NEXT: [[EndDisp:0x[A-F0-9]+]] IMAGE_REL_AMD64_ADDR32NB smallFunc +// CHECK-NEXT: [[UnwindDisp:0x[A-F0-9]+]] IMAGE_REL_AMD64_ADDR32NB .xdata +// CHECK-NEXT: ] +// CHECK: SectionData ( +// CHECK-NEXT: 0000: 00000000 01000000 00000000 +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK: UnwindInformation [ +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: StartAddress: smallFunc {{(\+0x[A-F0-9]+ )?}}([[BeginDisp]]) +// CHECK-NEXT: EndAddress: smallFunc {{(\+0x[A-F0-9]+ )?}}([[EndDisp]]) +// CHECK-NEXT: UnwindInfoAddress: .xdata {{(\+0x[A-F0-9]+ )?}}([[UnwindDisp]]) +// CHECK-NEXT: UnwindInfo { +// CHECK-NEXT: Version: 1 +// CHECK-NEXT: Flags [ +// CHECK-NEXT: ] +// CHECK-NEXT: PrologSize: 0 +// CHECK-NEXT: FrameRegister: - +// CHECK-NEXT: FrameOffset: - +// CHECK-NEXT: UnwindCodeCount: 0 +// CHECK-NEXT: UnwindCodes [ +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ] + +// Generate the minimal unwind info. +// It contains only the version set to 1. All other bytes are 0. + .globl smallFunc + .def smallFunc; .scl 2; .type 32; .endef + .seh_proc smallFunc +smallFunc: + ret + .seh_endproc diff --git a/test/MC/COFF/seh-align2.s b/test/MC/COFF/seh-align2.s new file mode 100644 index 00000000000..5e6c49a720c --- /dev/null +++ b/test/MC/COFF/seh-align2.s @@ -0,0 +1,78 @@ +// This test checks the alignment and padding of the unwind info. + +// RUN: llvm-mc -triple x86_64-pc-win32 -filetype=obj %s | llvm-readobj -s -sd -sr -u | FileCheck %s + +// CHECK: Sections [ +// CHECK: Section { +// CHECK: Name: .xdata +// CHECK: RawDataSize: 16 +// CHECK: RelocationCount: 1 +// CHECK: Characteristics [ +// CHECK-NEXT: ALIGN_4BYTES +// CHECK-NEXT: CNT_INITIALIZED_DATA +// CHECK-NEXT: MEM_READ +// CHECK-NEXT: ] +// CHECK: Relocations [ +// CHECK-NEXT: [[HandlerDisp:0x[A-F0-9]+]] IMAGE_REL_AMD64_ADDR32NB __C_specific_handler +// CHECK-NEXT: ] +// CHECK: SectionData ( +// CHECK-NEXT: 0000: 09000100 04220000 00000000 BEBAFECA +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT: Section { +// CHECK: Name: .pdata +// CHECK: RawDataSize: 12 +// CHECK: RelocationCount: 3 +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_4BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: ] +// CHECK: Relocations [ +// CHECK-NEXT: [[BeginDisp:0x[A-F0-9]+]] IMAGE_REL_AMD64_ADDR32NB func +// CHECK-NEXT: [[EndDisp:0x[A-F0-9]+]] IMAGE_REL_AMD64_ADDR32NB func +// CHECK-NEXT: [[UnwindDisp:0x[A-F0-9]+]] IMAGE_REL_AMD64_ADDR32NB .xdata +// CHECK-NEXT: ] +// CHECK: SectionData ( +// CHECK-NEXT: 0000: FCFFFFFF 05000000 00000000 +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK: UnwindInformation [ +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: StartAddress: func {{(\+0x[A-F0-9]+ )?}}([[BeginDisp]]) +// CHECK-NEXT: EndAddress: func {{(\+0x[A-F0-9]+ )?}}([[EndDisp]]) +// CHECK-NEXT: UnwindInfoAddress: .xdata {{(\+0x[A-F0-9]+ )?}}([[UnwindDisp]]) +// CHECK-NEXT: UnwindInfo { +// CHECK-NEXT: Version: 1 +// CHECK-NEXT: Flags [ +// CHECK-NEXT: ExceptionHandler +// CHECK-NEXT: ] +// CHECK-NEXT: PrologSize: 0 +// CHECK-NEXT: FrameRegister: - +// CHECK-NEXT: FrameOffset: - +// CHECK-NEXT: UnwindCodeCount: 1 +// CHECK-NEXT: UnwindCodes [ +// CHECK-NEXT: 0x04: ALLOC_SMALL size=24 +// CHECK-NEXT: ] +// CHECK-NEXT: Handler: __C_specific_handler ([[HandlerDisp]]) +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ] + +// Generates only one unwind code. +// Requires padding of the unwind code array. + .globl func + .def func; .scl 2; .type 32; .endef + .seh_proc func + subq $24, %rsp + .seh_stackalloc 24 + .seh_handler __C_specific_handler, @except + .seh_handlerdata + .long 0xcafebabe + .text + .seh_endprologue +func: + addq $24, %rsp + ret + .seh_endproc diff --git a/test/MC/COFF/seh-align3.s b/test/MC/COFF/seh-align3.s new file mode 100644 index 00000000000..238b5de3564 --- /dev/null +++ b/test/MC/COFF/seh-align3.s @@ -0,0 +1,83 @@ +// This test checks the alignment and padding of the unwind info. + +// RUN: llvm-mc -triple x86_64-pc-win32 -filetype=obj %s | llvm-readobj -s -sd -sr -u | FileCheck %s + +// CHECK: Sections [ +// CHECK: Section { +// CHECK: Name: .xdata +// CHECK: RawDataSize: 16 +// CHECK: RelocationCount: 1 +// CHECK: Characteristics [ +// CHECK-NEXT: ALIGN_4BYTES +// CHECK-NEXT: CNT_INITIALIZED_DATA +// CHECK-NEXT: MEM_READ +// CHECK-NEXT: ] +// CHECK: Relocations [ +// CHECK-NEXT: [[HandlerDisp:0x[A-F0-9]+]] IMAGE_REL_AMD64_ADDR32NB __C_specific_handler +// CHECK-NEXT: ] +// CHECK: SectionData ( +// CHECK-NEXT: 0000: 19000200 04D002C0 00000000 BEBAFECA +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT: Section { +// CHECK: Name: .pdata +// CHECK: RawDataSize: 12 +// CHECK: RelocationCount: 3 +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_4BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: ] +// CHECK: Relocations [ +// CHECK-NEXT: [[BeginDisp:0x[A-F0-9]+]] IMAGE_REL_AMD64_ADDR32NB func +// CHECK-NEXT: [[EndDisp:0x[A-F0-9]+]] IMAGE_REL_AMD64_ADDR32NB func +// CHECK-NEXT: [[UnwindDisp:0x[A-F0-9]+]] IMAGE_REL_AMD64_ADDR32NB .xdata +// CHECK-NEXT: ] +// CHECK: SectionData ( +// CHECK-NEXT: 0000: FCFFFFFF 05000000 00000000 +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK: UnwindInformation [ +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: StartAddress: func {{(\+0x[A-F0-9]+ )?}}([[BeginDisp]]) +// CHECK-NEXT: EndAddress: func {{(\+0x[A-F0-9]+ )?}}([[EndDisp]]) +// CHECK-NEXT: UnwindInfoAddress: .xdata {{(\+0x[A-F0-9]+ )?}}([[UnwindDisp]]) +// CHECK-NEXT: UnwindInfo { +// CHECK-NEXT: Version: 1 +// CHECK-NEXT: Flags [ +// CHECK-NEXT: ExceptionHandler +// CHECK-NEXT: TerminateHandler +// CHECK-NEXT: ] +// CHECK-NEXT: PrologSize: 0 +// CHECK-NEXT: FrameRegister: - +// CHECK-NEXT: FrameOffset: - +// CHECK-NEXT: UnwindCodeCount: 2 +// CHECK-NEXT: UnwindCodes [ +// CHECK-NEXT: 0x04: PUSH_NONVOL reg=R13 +// CHECK-NEXT: 0x02: PUSH_NONVOL reg=R12 +// CHECK-NEXT: ] +// CHECK-NEXT: Handler: __C_specific_handler ([[HandlerDisp]]) +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ] + +// Generates two unwind codes. +// Requires no padding of the unwind code array. + .globl func + .def func; .scl 2; .type 32; .endef + .seh_proc func + push %r12 + .seh_pushreg 12 + push %r13 + .seh_pushreg 13 + .seh_handler __C_specific_handler, @except, @unwind + .seh_handlerdata + .long 0xcafebabe + .text + .seh_endprologue +func: + pop %r13 + pop %r12 + ret + .seh_endproc