Mercurial > hg > CbC > CbC_llvm
comparison lib/MC/MCWin64EH.cpp @ 77:54457678186b LLVM3.6
LLVM 3.6
author | Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 08 Sep 2014 22:06:00 +0900 |
parents | 95c75e76d11b |
children | afa8332a0e37 |
comparison
equal
deleted
inserted
replaced
34:e874dbf0ad9d | 77:54457678186b |
---|---|
13 #include "llvm/MC/MCExpr.h" | 13 #include "llvm/MC/MCExpr.h" |
14 #include "llvm/MC/MCObjectFileInfo.h" | 14 #include "llvm/MC/MCObjectFileInfo.h" |
15 #include "llvm/MC/MCSectionCOFF.h" | 15 #include "llvm/MC/MCSectionCOFF.h" |
16 #include "llvm/MC/MCStreamer.h" | 16 #include "llvm/MC/MCStreamer.h" |
17 #include "llvm/MC/MCSymbol.h" | 17 #include "llvm/MC/MCSymbol.h" |
18 #include "llvm/Support/Win64EH.h" | |
18 | 19 |
19 namespace llvm { | 20 namespace llvm { |
20 | 21 |
21 // NOTE: All relocations generated here are 4-byte image-relative. | 22 // NOTE: All relocations generated here are 4-byte image-relative. |
22 | 23 |
23 static uint8_t CountOfUnwindCodes(std::vector<MCWin64EHInstruction> &instArray){ | 24 static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) { |
24 uint8_t count = 0; | 25 uint8_t Count = 0; |
25 for (std::vector<MCWin64EHInstruction>::const_iterator I = instArray.begin(), | 26 for (const auto &I : Insns) { |
26 E = instArray.end(); I != E; ++I) { | 27 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) { |
27 switch (I->getOperation()) { | |
28 case Win64EH::UOP_PushNonVol: | 28 case Win64EH::UOP_PushNonVol: |
29 case Win64EH::UOP_AllocSmall: | 29 case Win64EH::UOP_AllocSmall: |
30 case Win64EH::UOP_SetFPReg: | 30 case Win64EH::UOP_SetFPReg: |
31 case Win64EH::UOP_PushMachFrame: | 31 case Win64EH::UOP_PushMachFrame: |
32 count += 1; | 32 Count += 1; |
33 break; | 33 break; |
34 case Win64EH::UOP_SaveNonVol: | 34 case Win64EH::UOP_SaveNonVol: |
35 case Win64EH::UOP_SaveXMM128: | 35 case Win64EH::UOP_SaveXMM128: |
36 count += 2; | 36 Count += 2; |
37 break; | 37 break; |
38 case Win64EH::UOP_SaveNonVolBig: | 38 case Win64EH::UOP_SaveNonVolBig: |
39 case Win64EH::UOP_SaveXMM128Big: | 39 case Win64EH::UOP_SaveXMM128Big: |
40 count += 3; | 40 Count += 3; |
41 break; | 41 break; |
42 case Win64EH::UOP_AllocLarge: | 42 case Win64EH::UOP_AllocLarge: |
43 if (I->getSize() > 512*1024-8) | 43 Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2; |
44 count += 3; | |
45 else | |
46 count += 2; | |
47 break; | 44 break; |
48 } | 45 } |
49 } | 46 } |
50 return count; | 47 return Count; |
51 } | 48 } |
52 | 49 |
53 static void EmitAbsDifference(MCStreamer &streamer, MCSymbol *lhs, | 50 static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, |
54 MCSymbol *rhs) { | 51 const MCSymbol *RHS) { |
55 MCContext &context = streamer.getContext(); | 52 MCContext &Context = Streamer.getContext(); |
56 const MCExpr *diff = MCBinaryExpr::CreateSub(MCSymbolRefExpr::Create( | 53 const MCExpr *Diff = |
57 lhs, context), | 54 MCBinaryExpr::CreateSub(MCSymbolRefExpr::Create(LHS, Context), |
58 MCSymbolRefExpr::Create( | 55 MCSymbolRefExpr::Create(RHS, Context), Context); |
59 rhs, context), | 56 Streamer.EmitValue(Diff, 1); |
60 context); | 57 } |
61 streamer.EmitAbsValue(diff, 1); | 58 |
62 | 59 static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, |
63 } | 60 WinEH::Instruction &inst) { |
64 | |
65 static void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin, | |
66 MCWin64EHInstruction &inst) { | |
67 uint8_t b2; | 61 uint8_t b2; |
68 uint16_t w; | 62 uint16_t w; |
69 b2 = (inst.getOperation() & 0x0F); | 63 b2 = (inst.Operation & 0x0F); |
70 switch (inst.getOperation()) { | 64 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) { |
71 case Win64EH::UOP_PushNonVol: | 65 case Win64EH::UOP_PushNonVol: |
72 EmitAbsDifference(streamer, inst.getLabel(), begin); | 66 EmitAbsDifference(streamer, inst.Label, begin); |
73 b2 |= (inst.getRegister() & 0x0F) << 4; | 67 b2 |= (inst.Register & 0x0F) << 4; |
74 streamer.EmitIntValue(b2, 1); | 68 streamer.EmitIntValue(b2, 1); |
75 break; | 69 break; |
76 case Win64EH::UOP_AllocLarge: | 70 case Win64EH::UOP_AllocLarge: |
77 EmitAbsDifference(streamer, inst.getLabel(), begin); | 71 EmitAbsDifference(streamer, inst.Label, begin); |
78 if (inst.getSize() > 512*1024-8) { | 72 if (inst.Offset > 512 * 1024 - 8) { |
79 b2 |= 0x10; | 73 b2 |= 0x10; |
80 streamer.EmitIntValue(b2, 1); | 74 streamer.EmitIntValue(b2, 1); |
81 w = inst.getSize() & 0xFFF8; | 75 w = inst.Offset & 0xFFF8; |
82 streamer.EmitIntValue(w, 2); | 76 streamer.EmitIntValue(w, 2); |
83 w = inst.getSize() >> 16; | 77 w = inst.Offset >> 16; |
84 } else { | 78 } else { |
85 streamer.EmitIntValue(b2, 1); | 79 streamer.EmitIntValue(b2, 1); |
86 w = inst.getSize() >> 3; | 80 w = inst.Offset >> 3; |
87 } | 81 } |
88 streamer.EmitIntValue(w, 2); | 82 streamer.EmitIntValue(w, 2); |
89 break; | 83 break; |
90 case Win64EH::UOP_AllocSmall: | 84 case Win64EH::UOP_AllocSmall: |
91 b2 |= (((inst.getSize()-8) >> 3) & 0x0F) << 4; | 85 b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4; |
92 EmitAbsDifference(streamer, inst.getLabel(), begin); | 86 EmitAbsDifference(streamer, inst.Label, begin); |
93 streamer.EmitIntValue(b2, 1); | 87 streamer.EmitIntValue(b2, 1); |
94 break; | 88 break; |
95 case Win64EH::UOP_SetFPReg: | 89 case Win64EH::UOP_SetFPReg: |
96 EmitAbsDifference(streamer, inst.getLabel(), begin); | 90 EmitAbsDifference(streamer, inst.Label, begin); |
97 streamer.EmitIntValue(b2, 1); | 91 streamer.EmitIntValue(b2, 1); |
98 break; | 92 break; |
99 case Win64EH::UOP_SaveNonVol: | 93 case Win64EH::UOP_SaveNonVol: |
100 case Win64EH::UOP_SaveXMM128: | 94 case Win64EH::UOP_SaveXMM128: |
101 b2 |= (inst.getRegister() & 0x0F) << 4; | 95 b2 |= (inst.Register & 0x0F) << 4; |
102 EmitAbsDifference(streamer, inst.getLabel(), begin); | 96 EmitAbsDifference(streamer, inst.Label, begin); |
103 streamer.EmitIntValue(b2, 1); | 97 streamer.EmitIntValue(b2, 1); |
104 w = inst.getOffset() >> 3; | 98 w = inst.Offset >> 3; |
105 if (inst.getOperation() == Win64EH::UOP_SaveXMM128) | 99 if (inst.Operation == Win64EH::UOP_SaveXMM128) |
106 w >>= 1; | 100 w >>= 1; |
107 streamer.EmitIntValue(w, 2); | 101 streamer.EmitIntValue(w, 2); |
108 break; | 102 break; |
109 case Win64EH::UOP_SaveNonVolBig: | 103 case Win64EH::UOP_SaveNonVolBig: |
110 case Win64EH::UOP_SaveXMM128Big: | 104 case Win64EH::UOP_SaveXMM128Big: |
111 b2 |= (inst.getRegister() & 0x0F) << 4; | 105 b2 |= (inst.Register & 0x0F) << 4; |
112 EmitAbsDifference(streamer, inst.getLabel(), begin); | 106 EmitAbsDifference(streamer, inst.Label, begin); |
113 streamer.EmitIntValue(b2, 1); | 107 streamer.EmitIntValue(b2, 1); |
114 if (inst.getOperation() == Win64EH::UOP_SaveXMM128Big) | 108 if (inst.Operation == Win64EH::UOP_SaveXMM128Big) |
115 w = inst.getOffset() & 0xFFF0; | 109 w = inst.Offset & 0xFFF0; |
116 else | 110 else |
117 w = inst.getOffset() & 0xFFF8; | 111 w = inst.Offset & 0xFFF8; |
118 streamer.EmitIntValue(w, 2); | 112 streamer.EmitIntValue(w, 2); |
119 w = inst.getOffset() >> 16; | 113 w = inst.Offset >> 16; |
120 streamer.EmitIntValue(w, 2); | 114 streamer.EmitIntValue(w, 2); |
121 break; | 115 break; |
122 case Win64EH::UOP_PushMachFrame: | 116 case Win64EH::UOP_PushMachFrame: |
123 if (inst.isPushCodeFrame()) | 117 if (inst.Offset == 1) |
124 b2 |= 0x10; | 118 b2 |= 0x10; |
125 EmitAbsDifference(streamer, inst.getLabel(), begin); | 119 EmitAbsDifference(streamer, inst.Label, begin); |
126 streamer.EmitIntValue(b2, 1); | 120 streamer.EmitIntValue(b2, 1); |
127 break; | 121 break; |
128 } | 122 } |
129 } | 123 } |
130 | 124 |
140 Context); | 134 Context); |
141 streamer.EmitValue(MCBinaryExpr::CreateAdd(BaseRefRel, Ofs, Context), 4); | 135 streamer.EmitValue(MCBinaryExpr::CreateAdd(BaseRefRel, Ofs, Context), 4); |
142 } | 136 } |
143 | 137 |
144 static void EmitRuntimeFunction(MCStreamer &streamer, | 138 static void EmitRuntimeFunction(MCStreamer &streamer, |
145 const MCWin64EHUnwindInfo *info) { | 139 const WinEH::FrameInfo *info) { |
146 MCContext &context = streamer.getContext(); | 140 MCContext &context = streamer.getContext(); |
147 | 141 |
148 streamer.EmitValueToAlignment(4); | 142 streamer.EmitValueToAlignment(4); |
149 EmitSymbolRefWithOfs(streamer, info->Function, info->Begin); | 143 EmitSymbolRefWithOfs(streamer, info->Function, info->Begin); |
150 EmitSymbolRefWithOfs(streamer, info->Function, info->End); | 144 EmitSymbolRefWithOfs(streamer, info->Function, info->End); |
151 streamer.EmitValue(MCSymbolRefExpr::Create(info->Symbol, | 145 streamer.EmitValue(MCSymbolRefExpr::Create(info->Symbol, |
152 MCSymbolRefExpr::VK_COFF_IMGREL32, | 146 MCSymbolRefExpr::VK_COFF_IMGREL32, |
153 context), 4); | 147 context), 4); |
154 } | 148 } |
155 | 149 |
156 static void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) { | 150 static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) { |
157 // If this UNWIND_INFO already has a symbol, it's already been emitted. | 151 // If this UNWIND_INFO already has a symbol, it's already been emitted. |
158 if (info->Symbol) return; | 152 if (info->Symbol) |
153 return; | |
159 | 154 |
160 MCContext &context = streamer.getContext(); | 155 MCContext &context = streamer.getContext(); |
156 MCSymbol *Label = context.CreateTempSymbol(); | |
157 | |
161 streamer.EmitValueToAlignment(4); | 158 streamer.EmitValueToAlignment(4); |
162 info->Symbol = context.CreateTempSymbol(); | 159 streamer.EmitLabel(Label); |
163 streamer.EmitLabel(info->Symbol); | 160 info->Symbol = Label; |
164 | 161 |
165 // Upper 3 bits are the version number (currently 1). | 162 // Upper 3 bits are the version number (currently 1). |
166 uint8_t flags = 0x01; | 163 uint8_t flags = 0x01; |
167 if (info->ChainedParent) | 164 if (info->ChainedParent) |
168 flags |= Win64EH::UNW_ChainInfo << 3; | 165 flags |= Win64EH::UNW_ChainInfo << 3; |
182 uint8_t numCodes = CountOfUnwindCodes(info->Instructions); | 179 uint8_t numCodes = CountOfUnwindCodes(info->Instructions); |
183 streamer.EmitIntValue(numCodes, 1); | 180 streamer.EmitIntValue(numCodes, 1); |
184 | 181 |
185 uint8_t frame = 0; | 182 uint8_t frame = 0; |
186 if (info->LastFrameInst >= 0) { | 183 if (info->LastFrameInst >= 0) { |
187 MCWin64EHInstruction &frameInst = info->Instructions[info->LastFrameInst]; | 184 WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst]; |
188 assert(frameInst.getOperation() == Win64EH::UOP_SetFPReg); | 185 assert(frameInst.Operation == Win64EH::UOP_SetFPReg); |
189 frame = (frameInst.getRegister() & 0x0F) | | 186 frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0); |
190 (frameInst.getOffset() & 0xF0); | |
191 } | 187 } |
192 streamer.EmitIntValue(frame, 1); | 188 streamer.EmitIntValue(frame, 1); |
193 | 189 |
194 // Emit unwind instructions (in reverse order). | 190 // Emit unwind instructions (in reverse order). |
195 uint8_t numInst = info->Instructions.size(); | 191 uint8_t numInst = info->Instructions.size(); |
196 for (uint8_t c = 0; c < numInst; ++c) { | 192 for (uint8_t c = 0; c < numInst; ++c) { |
197 MCWin64EHInstruction inst = info->Instructions.back(); | 193 WinEH::Instruction inst = info->Instructions.back(); |
198 info->Instructions.pop_back(); | 194 info->Instructions.pop_back(); |
199 EmitUnwindCode(streamer, info->Begin, inst); | 195 EmitUnwindCode(streamer, info->Begin, inst); |
200 } | 196 } |
201 | 197 |
202 // For alignment purposes, the instruction array will always have an even | 198 // For alignment purposes, the instruction array will always have an even |
220 // than 2 slots used in the unwind code array, we have to pad to 8 bytes. | 216 // than 2 slots used in the unwind code array, we have to pad to 8 bytes. |
221 streamer.EmitIntValue(0, 4); | 217 streamer.EmitIntValue(0, 4); |
222 } | 218 } |
223 } | 219 } |
224 | 220 |
225 StringRef MCWin64EHUnwindEmitter::GetSectionSuffix(const MCSymbol *func) { | 221 namespace Win64EH { |
226 if (!func || !func->isInSection()) return ""; | 222 void UnwindEmitter::Emit(MCStreamer &Streamer) const { |
227 const MCSection *section = &func->getSection(); | 223 MCContext &Context = Streamer.getContext(); |
228 const MCSectionCOFF *COFFSection; | 224 |
229 if ((COFFSection = dyn_cast<MCSectionCOFF>(section))) { | 225 // Emit the unwind info structs first. |
230 StringRef name = COFFSection->getSectionName(); | 226 for (const auto &CFI : Streamer.getWinFrameInfos()) { |
231 size_t dollar = name.find('$'); | 227 const MCSection *XData = |
232 size_t dot = name.find('.', 1); | 228 getXDataSection(CFI->Function, Context); |
233 if (dollar == StringRef::npos && dot == StringRef::npos) | 229 Streamer.SwitchSection(XData); |
234 return ""; | 230 EmitUnwindInfo(Streamer, CFI); |
235 if (dot == StringRef::npos) | 231 } |
236 return name.substr(dollar); | 232 |
237 if (dollar == StringRef::npos || dot < dollar) | 233 // Now emit RUNTIME_FUNCTION entries. |
238 return name.substr(dot); | 234 for (const auto &CFI : Streamer.getWinFrameInfos()) { |
239 return name.substr(dollar); | 235 const MCSection *PData = |
240 } | 236 getPDataSection(CFI->Function, Context); |
241 return ""; | 237 Streamer.SwitchSection(PData); |
242 } | 238 EmitRuntimeFunction(Streamer, CFI); |
243 | 239 } |
244 static const MCSection *getWin64EHTableSection(StringRef suffix, | 240 } |
245 MCContext &context) { | 241 |
246 if (suffix == "") | 242 void UnwindEmitter::EmitUnwindInfo(MCStreamer &Streamer, |
247 return context.getObjectFileInfo()->getXDataSection(); | 243 WinEH::FrameInfo *info) const { |
248 | |
249 return context.getCOFFSection((".xdata"+suffix).str(), | |
250 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | | |
251 COFF::IMAGE_SCN_MEM_READ, | |
252 SectionKind::getDataRel()); | |
253 } | |
254 | |
255 static const MCSection *getWin64EHFuncTableSection(StringRef suffix, | |
256 MCContext &context) { | |
257 if (suffix == "") | |
258 return context.getObjectFileInfo()->getPDataSection(); | |
259 return context.getCOFFSection((".pdata"+suffix).str(), | |
260 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | | |
261 COFF::IMAGE_SCN_MEM_READ, | |
262 SectionKind::getDataRel()); | |
263 } | |
264 | |
265 void MCWin64EHUnwindEmitter::EmitUnwindInfo(MCStreamer &streamer, | |
266 MCWin64EHUnwindInfo *info) { | |
267 // Switch sections (the static function above is meant to be called from | 244 // Switch sections (the static function above is meant to be called from |
268 // here and from Emit(). | 245 // here and from Emit(). |
269 MCContext &context = streamer.getContext(); | 246 MCContext &context = Streamer.getContext(); |
270 const MCSection *xdataSect = | 247 const MCSection *xdataSect = |
271 getWin64EHTableSection(GetSectionSuffix(info->Function), context); | 248 getXDataSection(info->Function, context); |
272 streamer.SwitchSection(xdataSect); | 249 Streamer.SwitchSection(xdataSect); |
273 | 250 |
274 llvm::EmitUnwindInfo(streamer, info); | 251 llvm::EmitUnwindInfo(Streamer, info); |
275 } | 252 } |
276 | 253 } |
277 void MCWin64EHUnwindEmitter::Emit(MCStreamer &streamer) { | |
278 MCContext &context = streamer.getContext(); | |
279 // Emit the unwind info structs first. | |
280 for (unsigned i = 0; i < streamer.getNumW64UnwindInfos(); ++i) { | |
281 MCWin64EHUnwindInfo &info = streamer.getW64UnwindInfo(i); | |
282 const MCSection *xdataSect = | |
283 getWin64EHTableSection(GetSectionSuffix(info.Function), context); | |
284 streamer.SwitchSection(xdataSect); | |
285 llvm::EmitUnwindInfo(streamer, &info); | |
286 } | |
287 // Now emit RUNTIME_FUNCTION entries. | |
288 for (unsigned i = 0; i < streamer.getNumW64UnwindInfos(); ++i) { | |
289 MCWin64EHUnwindInfo &info = streamer.getW64UnwindInfo(i); | |
290 const MCSection *pdataSect = | |
291 getWin64EHFuncTableSection(GetSectionSuffix(info.Function), context); | |
292 streamer.SwitchSection(pdataSect); | |
293 EmitRuntimeFunction(streamer, &info); | |
294 } | |
295 } | |
296 | |
297 } // End of namespace llvm | 254 } // End of namespace llvm |
298 | 255 |