From 07cbe231738d64d830b77303d664b531130722f7 Mon Sep 17 00:00:00 2001 From: Charles Davis Date: Fri, 27 May 2011 15:10:25 +0000 Subject: [PATCH] Assorted fixes for Win64 EH unwind info emission: - Flip order of bitfields. This gets our output matching GAS. - Handle case where the end of the prolog wasn't specified. - If the resulting unwind info struct is less than 8 bytes, pad to 8 bytes. Add a test for the latter two. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@132188 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/MC/MCWin64EH.cpp | 45 ++++++++++++++++++++++++++++---------------- test/MC/COFF/seh.s | 17 +++++++++++++---- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/lib/MC/MCWin64EH.cpp b/lib/MC/MCWin64EH.cpp index c7141f7ad3c..018bb7cf6f8 100644 --- a/lib/MC/MCWin64EH.cpp +++ b/lib/MC/MCWin64EH.cpp @@ -63,17 +63,17 @@ static void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin, MCWin64EHInstruction &inst) { uint8_t b1, b2; uint16_t w; - b2 = (inst.getOperation() & 0x0F) << 4; + b2 = (inst.getOperation() & 0x0F); switch (inst.getOperation()) { case Win64EH::UOP_PushNonVol: EmitAbsDifference(streamer, inst.getLabel(), begin); - b2 |= inst.getRegister() & 0x0F; + b2 |= (inst.getRegister() & 0x0F) << 4; streamer.EmitIntValue(b2, 1); break; case Win64EH::UOP_AllocLarge: EmitAbsDifference(streamer, inst.getLabel(), begin); if (inst.getSize() > 512*1024-8) { - b2 |= 1; + b2 |= 0x10; streamer.EmitIntValue(b2, 1); w = inst.getSize() & 0xFFF8; streamer.EmitIntValue(w, 2); @@ -85,7 +85,7 @@ static void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin, streamer.EmitIntValue(w, 2); break; case Win64EH::UOP_AllocSmall: - b2 |= ((inst.getSize()-8) >> 3) & 0x0F; + b2 |= (((inst.getSize()-8) >> 3) & 0x0F) << 4; EmitAbsDifference(streamer, inst.getLabel(), begin); streamer.EmitIntValue(b2, 1); break; @@ -96,7 +96,7 @@ static void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin, break; case Win64EH::UOP_SaveNonVol: case Win64EH::UOP_SaveXMM128: - b2 |= inst.getRegister() & 0x0F; + b2 |= (inst.getRegister() & 0x0F) << 4; EmitAbsDifference(streamer, inst.getLabel(), begin); streamer.EmitIntValue(b2, 1); w = inst.getOffset() >> 3; @@ -106,7 +106,7 @@ static void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin, break; case Win64EH::UOP_SaveNonVolBig: case Win64EH::UOP_SaveXMM128Big: - b2 |= inst.getRegister() & 0x0F; + b2 |= (inst.getRegister() & 0x0F) << 4; EmitAbsDifference(streamer, inst.getLabel(), begin); streamer.EmitIntValue(b2, 1); if (inst.getOperation() == Win64EH::UOP_SaveXMM128Big) @@ -119,7 +119,7 @@ static void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin, break; case Win64EH::UOP_PushMachFrame: if (inst.isPushCodeFrame()) - b2 |= 1; + b2 |= 0x10; EmitAbsDifference(streamer, inst.getLabel(), begin); streamer.EmitIntValue(b2, 1); break; @@ -143,21 +143,24 @@ 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 = 0x20; + uint8_t flags = 0x01; info->Symbol = context.CreateTempSymbol(); streamer.EmitLabel(info->Symbol); if (info->ChainedParent) - flags |= Win64EH::UNW_ChainInfo; + flags |= Win64EH::UNW_ChainInfo << 3; else { if (info->HandlesUnwind) - flags |= Win64EH::UNW_TerminateHandler; + flags |= Win64EH::UNW_TerminateHandler << 3; if (info->HandlesExceptions) - flags |= Win64EH::UNW_ExceptionHandler; + flags |= Win64EH::UNW_ExceptionHandler << 3; } streamer.EmitIntValue(flags, 1); - EmitAbsDifference(streamer, info->PrologEnd, info->Begin); + if (info->PrologEnd) + EmitAbsDifference(streamer, info->PrologEnd, info->Begin); + else + streamer.EmitIntValue(0, 1); uint8_t numCodes = CountOfUnwindCodes(info->Instructions); streamer.EmitIntValue(numCodes, 1); @@ -166,8 +169,8 @@ static void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) { if (info->LastFrameInst >= 0) { MCWin64EHInstruction &frameInst = info->Instructions[info->LastFrameInst]; assert(frameInst.getOperation() == Win64EH::UOP_SetFPReg); - frame = ((frameInst.getRegister() & 0x0F) << 4) | - ((frameInst.getOffset() >> 4) & 0x0F); + frame = (frameInst.getRegister() & 0x0F) | + (frameInst.getOffset() & 0xF0); } streamer.EmitIntValue(frame, 1); @@ -179,11 +182,21 @@ static void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) { EmitUnwindCode(streamer, info->Begin, inst); } - if (flags & Win64EH::UNW_ChainInfo) + if (flags & (Win64EH::UNW_ChainInfo << 3)) EmitRuntimeFunction(streamer, info->ChainedParent); - else if (flags &(Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler)) + else if (flags & + ((Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler) << 3)) streamer.EmitValue(MCSymbolRefExpr::Create(info->ExceptionHandler, context), 4); + else if (numCodes < 2) { + // 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); + } } void MCWin64EHUnwindEmitter::EmitUnwindInfo(MCStreamer &streamer, diff --git a/test/MC/COFF/seh.s b/test/MC/COFF/seh.s index 236b13ff1c2..8cafcb3ab15 100644 --- a/test/MC/COFF/seh.s +++ b/test/MC/COFF/seh.s @@ -4,7 +4,7 @@ // CHECK: Name = .xdata // CHECK-NEXT: VirtualSize // CHECK-NEXT: VirtualAddress -// CHECK-NEXT: SizeOfRawData = 44 +// CHECK-NEXT: SizeOfRawData = 52 // CHECK-NEXT: PointerToRawData // CHECK-NEXT: PointerToRelocations // CHECK-NEXT: PointerToLineNumbers @@ -16,9 +16,10 @@ // CHECK-NEXT: IMAGE_SCN_MEM_READ // CHECK-NEXT: IMAGE_SCN_MEM_WRITE // CHECK-NEXT: SectionData -// CHECK-NEXT: 21 12 08 30 00 30 0F 03 - 0E 88 00 00 09 46 02 00 -// CHECK-NEXT: 04 22 00 A1 00 00 00 00 - 00 00 00 00 24 00 00 00 -// CHECK-NEXT: 00 00 00 00 1B 00 00 00 - 00 00 00 00 +// CHECK-NEXT: 09 12 08 03 00 03 0F 30 - 0E 88 00 00 09 64 02 00 +// CHECK-NEXT: 04 22 00 1A 00 00 00 00 - 00 00 00 00 21 00 00 00 +// CHECK-NEXT: 00 00 00 00 1B 00 00 00 - 00 00 00 00 01 00 00 00 +// CHECK-NEXT: 00 00 00 00 .text .globl func @@ -49,3 +50,11 @@ func: addq $24, %rsp ret .seh_endproc + +// Test emission of small functions. + .globl smallFunc + .def smallFunc; .scl 2; .type 32; .endef + .seh_proc smallFunc +smallFunc: + ret + .seh_endproc