diff --git a/include/llvm/MC/MCWin64EH.h b/include/llvm/MC/MCWin64EH.h index 39f30465466..5c0cfad7c36 100644 --- a/include/llvm/MC/MCWin64EH.h +++ b/include/llvm/MC/MCWin64EH.h @@ -28,30 +28,31 @@ namespace llvm { typedef Win64EH::UnwindOpcodes OpType; private: OpType Operation; + MCSymbol *Label; unsigned Offset; unsigned Register; public: - MCWin64EHInstruction(OpType Op, unsigned Reg) - : Operation(Op), Offset(0), Register(Reg) { - assert(Op == Win64EH::UOP_PushNonVol); + MCWin64EHInstruction(OpType Op, MCSymbol *L, unsigned Reg) + : Operation(Op), Label(L), Offset(0), Register(Reg) { + assert(Op == Win64EH::UOP_PushNonVol); } - MCWin64EHInstruction(unsigned Size) + MCWin64EHInstruction(MCSymbol *L, unsigned Size) : Operation(Size>128 ? Win64EH::UOP_AllocLarge : Win64EH::UOP_AllocSmall), - Offset(Size) { } - MCWin64EHInstruction(OpType Op, unsigned Reg, - unsigned Off) - : Operation(Op), Offset(Off), Register(Reg) { + Label(L), Offset(Size) { } + MCWin64EHInstruction(OpType Op, MCSymbol *L, unsigned Reg, unsigned Off) + : Operation(Op), Label(L), Offset(Off), Register(Reg) { assert(Op == Win64EH::UOP_SetFPReg || Op == Win64EH::UOP_SaveNonVol || Op == Win64EH::UOP_SaveNonVolBig || Op == Win64EH::UOP_SaveXMM128 || Op == Win64EH::UOP_SaveXMM128Big); } - MCWin64EHInstruction(OpType Op, bool Code) - : Operation(Op), Offset(Code ? 1 : 0) { + MCWin64EHInstruction(OpType Op, MCSymbol *L, bool Code) + : Operation(Op), Label(L), Offset(Code ? 1 : 0) { assert(Op == Win64EH::UOP_PushMachFrame); } OpType getOperation() const { return Operation; } + MCSymbol *getLabel() const { return Label; } unsigned getOffset() const { return Offset; } unsigned getSize() const { return Offset; } unsigned getRegister() const { return Register; } diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp index 881bc8eabae..974e885aacd 100644 --- a/lib/MC/MCStreamer.cpp +++ b/lib/MC/MCStreamer.cpp @@ -385,7 +385,9 @@ void MCStreamer::EmitWin64EHHandlerData() { void MCStreamer::EmitWin64EHPushReg(unsigned Register) { EnsureValidW64UnwindInfo(); MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; - MCWin64EHInstruction Inst(Win64EH::UOP_PushNonVol, Register); + MCSymbol *Label = getContext().CreateTempSymbol(); + MCWin64EHInstruction Inst(Win64EH::UOP_PushNonVol, Label, Register); + EmitLabel(Label); CurFrame->Instructions.push_back(Inst); } @@ -396,7 +398,7 @@ void MCStreamer::EmitWin64EHSetFrame(unsigned Register, unsigned Offset) { report_fatal_error("Frame register and offset already specified!"); if (Offset & 0x0F) report_fatal_error("Misaligned frame pointer offset!"); - MCWin64EHInstruction Inst(Win64EH::UOP_SetFPReg, Register, Offset); + MCWin64EHInstruction Inst(Win64EH::UOP_SetFPReg, NULL, Register, Offset); CurFrame->LastFrameInst = CurFrame->Instructions.size(); CurFrame->Instructions.push_back(Inst); } @@ -406,7 +408,9 @@ void MCStreamer::EmitWin64EHAllocStack(unsigned Size) { if (Size & 7) report_fatal_error("Misaligned stack allocation!"); MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; - MCWin64EHInstruction Inst(Size); + MCSymbol *Label = getContext().CreateTempSymbol(); + MCWin64EHInstruction Inst(Label, Size); + EmitLabel(Label); CurFrame->Instructions.push_back(Inst); } @@ -415,9 +419,11 @@ void MCStreamer::EmitWin64EHSaveReg(unsigned Register, unsigned Offset) { if (Offset & 7) report_fatal_error("Misaligned saved register offset!"); MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + MCSymbol *Label = getContext().CreateTempSymbol(); MCWin64EHInstruction Inst( Offset > 512*1024-8 ? Win64EH::UOP_SaveNonVolBig : Win64EH::UOP_SaveNonVol, - Register, Offset); + Label, Register, Offset); + EmitLabel(Label); CurFrame->Instructions.push_back(Inst); } @@ -426,9 +432,11 @@ void MCStreamer::EmitWin64EHSaveXMM(unsigned Register, unsigned Offset) { if (Offset & 0x0F) report_fatal_error("Misaligned saved vector register offset!"); MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + MCSymbol *Label = getContext().CreateTempSymbol(); MCWin64EHInstruction Inst( Offset > 512*1024-16 ? Win64EH::UOP_SaveXMM128Big : Win64EH::UOP_SaveXMM128, - Register, Offset); + Label, Register, Offset); + EmitLabel(Label); CurFrame->Instructions.push_back(Inst); } @@ -437,7 +445,9 @@ void MCStreamer::EmitWin64EHPushFrame(bool Code) { MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; if (CurFrame->Instructions.size() > 0) report_fatal_error("If present, PushMachFrame must be the first UOP"); - MCWin64EHInstruction Inst(Win64EH::UOP_PushMachFrame, Code); + MCSymbol *Label = getContext().CreateTempSymbol(); + MCWin64EHInstruction Inst(Win64EH::UOP_PushMachFrame, Label, Code); + EmitLabel(Label); CurFrame->Instructions.push_back(Inst); } diff --git a/lib/MC/MCWin64EH.cpp b/lib/MC/MCWin64EH.cpp index 2511e91b850..c7141f7ad3c 100644 --- a/lib/MC/MCWin64EH.cpp +++ b/lib/MC/MCWin64EH.cpp @@ -47,18 +47,31 @@ static uint8_t CountOfUnwindCodes(std::vector &instArray){ return count; } -static void EmitUnwindCode(MCStreamer &streamer, MCWin64EHInstruction &inst) { +static void EmitAbsDifference(MCStreamer &streamer, MCSymbol *lhs, + MCSymbol *rhs) { + MCContext &context = streamer.getContext(); + const MCExpr *diff = MCBinaryExpr::CreateSub(MCSymbolRefExpr::Create( + lhs, context), + MCSymbolRefExpr::Create( + rhs, context), + context); + streamer.EmitAbsValue(diff, 1); + +} + +static void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin, + MCWin64EHInstruction &inst) { uint8_t b1, b2; uint16_t w; b2 = (inst.getOperation() & 0x0F) << 4; switch (inst.getOperation()) { case Win64EH::UOP_PushNonVol: - streamer.EmitIntValue(0, 1); + EmitAbsDifference(streamer, inst.getLabel(), begin); b2 |= inst.getRegister() & 0x0F; streamer.EmitIntValue(b2, 1); break; case Win64EH::UOP_AllocLarge: - streamer.EmitIntValue(0, 1); + EmitAbsDifference(streamer, inst.getLabel(), begin); if (inst.getSize() > 512*1024-8) { b2 |= 1; streamer.EmitIntValue(b2, 1); @@ -72,8 +85,8 @@ static void EmitUnwindCode(MCStreamer &streamer, MCWin64EHInstruction &inst) { streamer.EmitIntValue(w, 2); break; case Win64EH::UOP_AllocSmall: - b2 |= (inst.getSize() >> 3) & 0x0F; - streamer.EmitIntValue(0, 1); + b2 |= ((inst.getSize()-8) >> 3) & 0x0F; + EmitAbsDifference(streamer, inst.getLabel(), begin); streamer.EmitIntValue(b2, 1); break; case Win64EH::UOP_SetFPReg: @@ -84,7 +97,7 @@ static void EmitUnwindCode(MCStreamer &streamer, MCWin64EHInstruction &inst) { case Win64EH::UOP_SaveNonVol: case Win64EH::UOP_SaveXMM128: b2 |= inst.getRegister() & 0x0F; - streamer.EmitIntValue(0, 1); + EmitAbsDifference(streamer, inst.getLabel(), begin); streamer.EmitIntValue(b2, 1); w = inst.getOffset() >> 3; if (inst.getOperation() == Win64EH::UOP_SaveXMM128) @@ -94,7 +107,7 @@ static void EmitUnwindCode(MCStreamer &streamer, MCWin64EHInstruction &inst) { case Win64EH::UOP_SaveNonVolBig: case Win64EH::UOP_SaveXMM128Big: b2 |= inst.getRegister() & 0x0F; - streamer.EmitIntValue(0, 1); + EmitAbsDifference(streamer, inst.getLabel(), begin); streamer.EmitIntValue(b2, 1); if (inst.getOperation() == Win64EH::UOP_SaveXMM128Big) w = inst.getOffset() & 0xFFF0; @@ -107,7 +120,7 @@ static void EmitUnwindCode(MCStreamer &streamer, MCWin64EHInstruction &inst) { case Win64EH::UOP_PushMachFrame: if (inst.isPushCodeFrame()) b2 |= 1; - streamer.EmitIntValue(0, 1); + EmitAbsDifference(streamer, inst.getLabel(), begin); streamer.EmitIntValue(b2, 1); break; } @@ -144,13 +157,7 @@ static void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) { } streamer.EmitIntValue(flags, 1); - // Build up the prolog size expression. - const MCExpr *prologSize = MCBinaryExpr::CreateSub(MCSymbolRefExpr::Create( - info->PrologEnd, context), - MCSymbolRefExpr::Create( - info->Begin, context), - context); - streamer.EmitAbsValue(prologSize, 1); + EmitAbsDifference(streamer, info->PrologEnd, info->Begin); uint8_t numCodes = CountOfUnwindCodes(info->Instructions); streamer.EmitIntValue(numCodes, 1); @@ -169,7 +176,7 @@ static void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) { for (uint8_t c = 0; c < numInst; ++c) { MCWin64EHInstruction inst = info->Instructions.back(); info->Instructions.pop_back(); - EmitUnwindCode(streamer, inst); + EmitUnwindCode(streamer, info->Begin, inst); } if (flags & Win64EH::UNW_ChainInfo)