MCWin64EH.cpp revision 3185f5c35322cbd10040ab20f265042d477efe62
1//===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "llvm/MC/MCWin64EH.h" 11#include "llvm/MC/MCStreamer.h" 12#include "llvm/MC/MCContext.h" 13#include "llvm/MC/MCExpr.h" 14#include "llvm/Target/TargetAsmInfo.h" 15 16namespace llvm { 17 18// NOTE: All relocations generated here are 4-byte image-relative. 19 20static uint8_t CountOfUnwindCodes(std::vector<MCWin64EHInstruction> &instArray){ 21 uint8_t count = 0; 22 for (std::vector<MCWin64EHInstruction>::const_iterator I = instArray.begin(), 23 E = instArray.end(); I != E; ++I) { 24 switch (I->getOperation()) { 25 case Win64EH::UOP_PushNonVol: 26 case Win64EH::UOP_AllocSmall: 27 case Win64EH::UOP_SetFPReg: 28 case Win64EH::UOP_PushMachFrame: 29 count += 1; 30 case Win64EH::UOP_SaveNonVol: 31 case Win64EH::UOP_SaveXMM128: 32 count += 2; 33 case Win64EH::UOP_SaveNonVolBig: 34 case Win64EH::UOP_SaveXMM128Big: 35 count += 3; 36 case Win64EH::UOP_AllocLarge: 37 if (I->getSize() > 512*1024-8) 38 count += 3; 39 else 40 count += 2; 41 } 42 } 43 return count; 44} 45 46static void EmitUnwindCode(MCStreamer &streamer, MCWin64EHInstruction &inst) { 47 uint8_t b1, b2; 48 uint16_t w; 49 b2 = (inst.getOperation() & 0x0F) << 4; 50 switch (inst.getOperation()) { 51 case Win64EH::UOP_PushNonVol: 52 streamer.EmitIntValue(0, 1); 53 b2 |= inst.getRegister() & 0x0F; 54 streamer.EmitIntValue(b2, 1); 55 break; 56 case Win64EH::UOP_AllocLarge: 57 streamer.EmitIntValue(0, 1); 58 if (inst.getSize() > 512*1024-8) { 59 b2 |= 1; 60 streamer.EmitIntValue(b2, 1); 61 w = inst.getSize() & 0xFFF8; 62 streamer.EmitIntValue(w, 2); 63 w = inst.getSize() >> 16; 64 } else { 65 streamer.EmitIntValue(b2, 1); 66 w = inst.getSize() >> 3; 67 } 68 streamer.EmitIntValue(w, 2); 69 break; 70 case Win64EH::UOP_AllocSmall: 71 b2 |= (inst.getSize() >> 3) & 0x0F; 72 streamer.EmitIntValue(0, 1); 73 streamer.EmitIntValue(b2, 1); 74 break; 75 case Win64EH::UOP_SetFPReg: 76 b1 = inst.getOffset() & 0xF0; 77 streamer.EmitIntValue(b1, 1); 78 streamer.EmitIntValue(b2, 1); 79 break; 80 case Win64EH::UOP_SaveNonVol: 81 case Win64EH::UOP_SaveXMM128: 82 b2 |= inst.getRegister() & 0x0F; 83 streamer.EmitIntValue(0, 1); 84 streamer.EmitIntValue(b2, 1); 85 w = inst.getOffset() >> 3; 86 if (inst.getOperation() == Win64EH::UOP_SaveXMM128) 87 w >>= 1; 88 streamer.EmitIntValue(w, 2); 89 break; 90 case Win64EH::UOP_SaveNonVolBig: 91 case Win64EH::UOP_SaveXMM128Big: 92 b2 |= inst.getRegister() & 0x0F; 93 streamer.EmitIntValue(0, 1); 94 streamer.EmitIntValue(b2, 1); 95 if (inst.getOperation() == Win64EH::UOP_SaveXMM128Big) 96 w = inst.getOffset() & 0xFFF0; 97 else 98 w = inst.getOffset() & 0xFFF8; 99 streamer.EmitIntValue(w, 2); 100 w = inst.getOffset() >> 16; 101 streamer.EmitIntValue(w, 2); 102 break; 103 case Win64EH::UOP_PushMachFrame: 104 if (inst.isPushCodeFrame()) 105 b2 |= 1; 106 streamer.EmitIntValue(0, 1); 107 streamer.EmitIntValue(b2, 1); 108 break; 109 } 110} 111 112static void EmitRuntimeFunction(MCStreamer &streamer, 113 MCWin64EHUnwindInfo *info) { 114 MCContext &context = streamer.getContext(); 115 116 streamer.EmitValue(MCSymbolRefExpr::Create(info->Begin, context), 4); 117 streamer.EmitValue(MCSymbolRefExpr::Create(info->End, context), 4); 118 streamer.EmitValue(MCSymbolRefExpr::Create(info->Symbol, context), 4); 119} 120 121static void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) { 122 // If this UNWIND_INFO already has a symbol, it's already been emitted. 123 if (info->Symbol) return; 124 125 MCContext &context = streamer.getContext(); 126 // Upper 3 bits are the version number (currently 1). 127 uint8_t flags = 0x20; 128 info->Symbol = context.CreateTempSymbol(); 129 streamer.EmitLabel(info->Symbol); 130 131 if (info->ChainedParent) 132 flags |= Win64EH::UNW_ChainInfo; 133 else { 134 if (info->HandlesUnwind) 135 flags |= Win64EH::UNW_TerminateHandler; 136 if (info->HandlesExceptions) 137 flags |= Win64EH::UNW_ExceptionHandler; 138 } 139 streamer.EmitIntValue(flags, 1); 140 141 // Build up the prolog size expression. 142 const MCExpr *prologSize = MCBinaryExpr::CreateSub(MCSymbolRefExpr::Create( 143 info->PrologEnd, context), 144 MCSymbolRefExpr::Create( 145 info->Begin, context), 146 context); 147 streamer.EmitAbsValue(prologSize, 1); 148 149 uint8_t numCodes = CountOfUnwindCodes(info->Instructions); 150 streamer.EmitIntValue(numCodes, 1); 151 152 uint8_t frame = 0; 153 if (info->LastFrameInst >= 0) { 154 MCWin64EHInstruction &frameInst = info->Instructions[info->LastFrameInst]; 155 assert(frameInst.getOperation() == Win64EH::UOP_SetFPReg); 156 frame = ((frameInst.getRegister() & 0x0F) << 4) | 157 ((frameInst.getOffset() >> 4) & 0x0F); 158 } 159 streamer.EmitIntValue(frame, 1); 160 161 // Emit unwind instructions (in reverse order). 162 uint8_t numInst = info->Instructions.size(); 163 for (uint8_t c = 0; c < numInst; ++c) { 164 MCWin64EHInstruction inst = info->Instructions.back(); 165 info->Instructions.pop_back(); 166 EmitUnwindCode(streamer, inst); 167 } 168 169 if (flags & Win64EH::UNW_ChainInfo) 170 EmitRuntimeFunction(streamer, info->ChainedParent); 171 else if (flags &(Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler)) 172 streamer.EmitValue(MCSymbolRefExpr::Create(info->ExceptionHandler, context), 173 4); 174} 175 176void MCWin64EHUnwindEmitter::EmitUnwindInfo(MCStreamer &streamer, 177 MCWin64EHUnwindInfo *info) { 178 // Switch sections (the static function above is meant to be called from 179 // here and from Emit(). 180 MCContext &context = streamer.getContext(); 181 const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); 182 const MCSection *xdataSect = asmInfo.getWin64EHTableSection(); 183 streamer.SwitchSection(xdataSect); 184 185 llvm::EmitUnwindInfo(streamer, info); 186} 187 188} // End of namespace llvm 189 190