1 //===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/MC/MCWin64EH.h"
11 #include "llvm/ADT/Twine.h"
12 #include "llvm/MC/MCContext.h"
13 #include "llvm/MC/MCExpr.h"
14 #include "llvm/MC/MCObjectFileInfo.h"
15 #include "llvm/MC/MCSectionCOFF.h"
16 #include "llvm/MC/MCStreamer.h"
17 #include "llvm/MC/MCSymbol.h"
21 // NOTE: All relocations generated here are 4-byte image-relative.
23 static uint8_t CountOfUnwindCodes(std::vector<MCWin64EHInstruction> &Insns) {
25 for (const auto &I : Insns) {
26 switch (I.Operation) {
27 case Win64EH::UOP_PushNonVol:
28 case Win64EH::UOP_AllocSmall:
29 case Win64EH::UOP_SetFPReg:
30 case Win64EH::UOP_PushMachFrame:
33 case Win64EH::UOP_SaveNonVol:
34 case Win64EH::UOP_SaveXMM128:
37 case Win64EH::UOP_SaveNonVolBig:
38 case Win64EH::UOP_SaveXMM128Big:
41 case Win64EH::UOP_AllocLarge:
42 Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2;
49 static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
50 const MCSymbol *RHS) {
51 MCContext &Context = Streamer.getContext();
53 MCBinaryExpr::CreateSub(MCSymbolRefExpr::Create(LHS, Context),
54 MCSymbolRefExpr::Create(RHS, Context), Context);
55 Streamer.EmitAbsValue(Diff, 1);
58 static void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin,
59 MCWin64EHInstruction &inst) {
62 b2 = (inst.Operation & 0x0F);
63 switch (inst.Operation) {
64 case Win64EH::UOP_PushNonVol:
65 EmitAbsDifference(streamer, inst.Label, begin);
66 b2 |= (inst.Register & 0x0F) << 4;
67 streamer.EmitIntValue(b2, 1);
69 case Win64EH::UOP_AllocLarge:
70 EmitAbsDifference(streamer, inst.Label, begin);
71 if (inst.Offset > 512 * 1024 - 8) {
73 streamer.EmitIntValue(b2, 1);
74 w = inst.Offset & 0xFFF8;
75 streamer.EmitIntValue(w, 2);
76 w = inst.Offset >> 16;
78 streamer.EmitIntValue(b2, 1);
81 streamer.EmitIntValue(w, 2);
83 case Win64EH::UOP_AllocSmall:
84 b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4;
85 EmitAbsDifference(streamer, inst.Label, begin);
86 streamer.EmitIntValue(b2, 1);
88 case Win64EH::UOP_SetFPReg:
89 EmitAbsDifference(streamer, inst.Label, begin);
90 streamer.EmitIntValue(b2, 1);
92 case Win64EH::UOP_SaveNonVol:
93 case Win64EH::UOP_SaveXMM128:
94 b2 |= (inst.Register & 0x0F) << 4;
95 EmitAbsDifference(streamer, inst.Label, begin);
96 streamer.EmitIntValue(b2, 1);
98 if (inst.Operation == Win64EH::UOP_SaveXMM128)
100 streamer.EmitIntValue(w, 2);
102 case Win64EH::UOP_SaveNonVolBig:
103 case Win64EH::UOP_SaveXMM128Big:
104 b2 |= (inst.Register & 0x0F) << 4;
105 EmitAbsDifference(streamer, inst.Label, begin);
106 streamer.EmitIntValue(b2, 1);
107 if (inst.Operation == Win64EH::UOP_SaveXMM128Big)
108 w = inst.Offset & 0xFFF0;
110 w = inst.Offset & 0xFFF8;
111 streamer.EmitIntValue(w, 2);
112 w = inst.Offset >> 16;
113 streamer.EmitIntValue(w, 2);
115 case Win64EH::UOP_PushMachFrame:
116 if (inst.Offset == 1)
118 EmitAbsDifference(streamer, inst.Label, begin);
119 streamer.EmitIntValue(b2, 1);
124 static void EmitSymbolRefWithOfs(MCStreamer &streamer,
125 const MCSymbol *Base,
126 const MCSymbol *Other) {
127 MCContext &Context = streamer.getContext();
128 const MCSymbolRefExpr *BaseRef = MCSymbolRefExpr::Create(Base, Context);
129 const MCSymbolRefExpr *OtherRef = MCSymbolRefExpr::Create(Other, Context);
130 const MCExpr *Ofs = MCBinaryExpr::CreateSub(OtherRef, BaseRef, Context);
131 const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::Create(Base,
132 MCSymbolRefExpr::VK_COFF_IMGREL32,
134 streamer.EmitValue(MCBinaryExpr::CreateAdd(BaseRefRel, Ofs, Context), 4);
137 static void EmitRuntimeFunction(MCStreamer &streamer,
138 const MCWinFrameInfo *info) {
139 MCContext &context = streamer.getContext();
141 streamer.EmitValueToAlignment(4);
142 EmitSymbolRefWithOfs(streamer, info->Function, info->Begin);
143 EmitSymbolRefWithOfs(streamer, info->Function, info->End);
144 streamer.EmitValue(MCSymbolRefExpr::Create(info->Symbol,
145 MCSymbolRefExpr::VK_COFF_IMGREL32,
149 static void EmitUnwindInfo(MCStreamer &streamer, MCWinFrameInfo *info) {
150 // If this UNWIND_INFO already has a symbol, it's already been emitted.
151 if (info->Symbol) return;
153 MCContext &context = streamer.getContext();
154 streamer.EmitValueToAlignment(4);
155 info->Symbol = context.CreateTempSymbol();
156 streamer.EmitLabel(info->Symbol);
158 // Upper 3 bits are the version number (currently 1).
159 uint8_t flags = 0x01;
160 if (info->ChainedParent)
161 flags |= Win64EH::UNW_ChainInfo << 3;
163 if (info->HandlesUnwind)
164 flags |= Win64EH::UNW_TerminateHandler << 3;
165 if (info->HandlesExceptions)
166 flags |= Win64EH::UNW_ExceptionHandler << 3;
168 streamer.EmitIntValue(flags, 1);
171 EmitAbsDifference(streamer, info->PrologEnd, info->Begin);
173 streamer.EmitIntValue(0, 1);
175 uint8_t numCodes = CountOfUnwindCodes(info->Instructions);
176 streamer.EmitIntValue(numCodes, 1);
179 if (info->LastFrameInst >= 0) {
180 MCWin64EHInstruction &frameInst = info->Instructions[info->LastFrameInst];
181 assert(frameInst.Operation == Win64EH::UOP_SetFPReg);
182 frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0);
184 streamer.EmitIntValue(frame, 1);
186 // Emit unwind instructions (in reverse order).
187 uint8_t numInst = info->Instructions.size();
188 for (uint8_t c = 0; c < numInst; ++c) {
189 MCWin64EHInstruction inst = info->Instructions.back();
190 info->Instructions.pop_back();
191 EmitUnwindCode(streamer, info->Begin, inst);
194 // For alignment purposes, the instruction array will always have an even
195 // number of entries, with the final entry potentially unused (in which case
196 // the array will be one longer than indicated by the count of unwind codes
199 streamer.EmitIntValue(0, 2);
202 if (flags & (Win64EH::UNW_ChainInfo << 3))
203 EmitRuntimeFunction(streamer, info->ChainedParent);
205 ((Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler) << 3))
206 streamer.EmitValue(MCSymbolRefExpr::Create(info->ExceptionHandler,
207 MCSymbolRefExpr::VK_COFF_IMGREL32,
209 else if (numCodes == 0) {
210 // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not
211 // a chained unwind info, if there is no handler, and if there are fewer
212 // than 2 slots used in the unwind code array, we have to pad to 8 bytes.
213 streamer.EmitIntValue(0, 4);
217 StringRef MCWin64EHUnwindEmitter::GetSectionSuffix(const MCSymbol *func) {
218 if (!func || !func->isInSection()) return "";
219 const MCSection *section = &func->getSection();
220 const MCSectionCOFF *COFFSection;
221 if ((COFFSection = dyn_cast<MCSectionCOFF>(section))) {
222 StringRef name = COFFSection->getSectionName();
223 size_t dollar = name.find('$');
224 size_t dot = name.find('.', 1);
225 if (dollar == StringRef::npos && dot == StringRef::npos)
227 if (dot == StringRef::npos)
228 return name.substr(dollar);
229 if (dollar == StringRef::npos || dot < dollar)
230 return name.substr(dot);
231 return name.substr(dollar);
236 static const MCSection *getWin64EHTableSection(StringRef suffix,
237 MCContext &context) {
239 return context.getObjectFileInfo()->getXDataSection();
241 return context.getCOFFSection((".xdata"+suffix).str(),
242 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
243 COFF::IMAGE_SCN_MEM_READ,
244 SectionKind::getDataRel());
247 static const MCSection *getWin64EHFuncTableSection(StringRef suffix,
248 MCContext &context) {
250 return context.getObjectFileInfo()->getPDataSection();
251 return context.getCOFFSection((".pdata"+suffix).str(),
252 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
253 COFF::IMAGE_SCN_MEM_READ,
254 SectionKind::getDataRel());
257 void MCWin64EHUnwindEmitter::EmitUnwindInfo(MCStreamer &streamer,
258 MCWinFrameInfo *info) {
259 // Switch sections (the static function above is meant to be called from
260 // here and from Emit().
261 MCContext &context = streamer.getContext();
262 const MCSection *xdataSect =
263 getWin64EHTableSection(GetSectionSuffix(info->Function), context);
264 streamer.SwitchSection(xdataSect);
266 llvm::EmitUnwindInfo(streamer, info);
269 void MCWin64EHUnwindEmitter::Emit(MCStreamer &Streamer) {
270 MCContext &Context = Streamer.getContext();
272 // Emit the unwind info structs first.
273 for (const auto &CFI : Streamer.getWinFrameInfos()) {
274 const MCSection *XData =
275 getWin64EHTableSection(GetSectionSuffix(CFI->Function), Context);
276 Streamer.SwitchSection(XData);
277 EmitUnwindInfo(Streamer, CFI);
280 // Now emit RUNTIME_FUNCTION entries.
281 for (const auto &CFI : Streamer.getWinFrameInfos()) {
282 const MCSection *PData =
283 getWin64EHFuncTableSection(GetSectionSuffix(CFI->Function), Context);
284 Streamer.SwitchSection(PData);
285 EmitRuntimeFunction(Streamer, CFI);
289 } // End of namespace llvm