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/MC/MCStreamer.h"
12 #include "llvm/MC/MCContext.h"
13 #include "llvm/MC/MCSymbol.h"
14 #include "llvm/MC/MCSectionCOFF.h"
15 #include "llvm/MC/MCExpr.h"
16 #include "llvm/Target/TargetAsmInfo.h"
20 // NOTE: All relocations generated here are 4-byte image-relative.
22 static uint8_t CountOfUnwindCodes(std::vector
<MCWin64EHInstruction
> &instArray
){
24 for (std::vector
<MCWin64EHInstruction
>::const_iterator I
= instArray
.begin(),
25 E
= instArray
.end(); I
!= E
; ++I
) {
26 switch (I
->getOperation()) {
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 if (I
->getSize() > 512*1024-8)
52 static void EmitAbsDifference(MCStreamer
&streamer
, MCSymbol
*lhs
,
54 MCContext
&context
= streamer
.getContext();
55 const MCExpr
*diff
= MCBinaryExpr::CreateSub(MCSymbolRefExpr::Create(
57 MCSymbolRefExpr::Create(
60 streamer
.EmitAbsValue(diff
, 1);
64 static void EmitUnwindCode(MCStreamer
&streamer
, MCSymbol
*begin
,
65 MCWin64EHInstruction
&inst
) {
68 b2
= (inst
.getOperation() & 0x0F);
69 switch (inst
.getOperation()) {
70 case Win64EH::UOP_PushNonVol
:
71 EmitAbsDifference(streamer
, inst
.getLabel(), begin
);
72 b2
|= (inst
.getRegister() & 0x0F) << 4;
73 streamer
.EmitIntValue(b2
, 1);
75 case Win64EH::UOP_AllocLarge
:
76 EmitAbsDifference(streamer
, inst
.getLabel(), begin
);
77 if (inst
.getSize() > 512*1024-8) {
79 streamer
.EmitIntValue(b2
, 1);
80 w
= inst
.getSize() & 0xFFF8;
81 streamer
.EmitIntValue(w
, 2);
82 w
= inst
.getSize() >> 16;
84 streamer
.EmitIntValue(b2
, 1);
85 w
= inst
.getSize() >> 3;
87 streamer
.EmitIntValue(w
, 2);
89 case Win64EH::UOP_AllocSmall
:
90 b2
|= (((inst
.getSize()-8) >> 3) & 0x0F) << 4;
91 EmitAbsDifference(streamer
, inst
.getLabel(), begin
);
92 streamer
.EmitIntValue(b2
, 1);
94 case Win64EH::UOP_SetFPReg
:
95 b1
= inst
.getOffset() & 0xF0;
96 streamer
.EmitIntValue(b1
, 1);
97 streamer
.EmitIntValue(b2
, 1);
99 case Win64EH::UOP_SaveNonVol
:
100 case Win64EH::UOP_SaveXMM128
:
101 b2
|= (inst
.getRegister() & 0x0F) << 4;
102 EmitAbsDifference(streamer
, inst
.getLabel(), begin
);
103 streamer
.EmitIntValue(b2
, 1);
104 w
= inst
.getOffset() >> 3;
105 if (inst
.getOperation() == Win64EH::UOP_SaveXMM128
)
107 streamer
.EmitIntValue(w
, 2);
109 case Win64EH::UOP_SaveNonVolBig
:
110 case Win64EH::UOP_SaveXMM128Big
:
111 b2
|= (inst
.getRegister() & 0x0F) << 4;
112 EmitAbsDifference(streamer
, inst
.getLabel(), begin
);
113 streamer
.EmitIntValue(b2
, 1);
114 if (inst
.getOperation() == Win64EH::UOP_SaveXMM128Big
)
115 w
= inst
.getOffset() & 0xFFF0;
117 w
= inst
.getOffset() & 0xFFF8;
118 streamer
.EmitIntValue(w
, 2);
119 w
= inst
.getOffset() >> 16;
120 streamer
.EmitIntValue(w
, 2);
122 case Win64EH::UOP_PushMachFrame
:
123 if (inst
.isPushCodeFrame())
125 EmitAbsDifference(streamer
, inst
.getLabel(), begin
);
126 streamer
.EmitIntValue(b2
, 1);
131 static void EmitRuntimeFunction(MCStreamer
&streamer
,
132 const MCWin64EHUnwindInfo
*info
) {
133 MCContext
&context
= streamer
.getContext();
135 streamer
.EmitValueToAlignment(4);
136 streamer
.EmitValue(MCSymbolRefExpr::Create(info
->Begin
, context
), 4);
137 streamer
.EmitValue(MCSymbolRefExpr::Create(info
->End
, context
), 4);
138 streamer
.EmitValue(MCSymbolRefExpr::Create(info
->Symbol
, context
), 4);
141 static void EmitUnwindInfo(MCStreamer
&streamer
, MCWin64EHUnwindInfo
*info
) {
142 // If this UNWIND_INFO already has a symbol, it's already been emitted.
143 if (info
->Symbol
) return;
145 MCContext
&context
= streamer
.getContext();
146 streamer
.EmitValueToAlignment(4);
147 // Upper 3 bits are the version number (currently 1).
148 uint8_t flags
= 0x01;
149 info
->Symbol
= context
.CreateTempSymbol();
150 streamer
.EmitLabel(info
->Symbol
);
152 if (info
->ChainedParent
)
153 flags
|= Win64EH::UNW_ChainInfo
<< 3;
155 if (info
->HandlesUnwind
)
156 flags
|= Win64EH::UNW_TerminateHandler
<< 3;
157 if (info
->HandlesExceptions
)
158 flags
|= Win64EH::UNW_ExceptionHandler
<< 3;
160 streamer
.EmitIntValue(flags
, 1);
163 EmitAbsDifference(streamer
, info
->PrologEnd
, info
->Begin
);
165 streamer
.EmitIntValue(0, 1);
167 uint8_t numCodes
= CountOfUnwindCodes(info
->Instructions
);
168 streamer
.EmitIntValue(numCodes
, 1);
171 if (info
->LastFrameInst
>= 0) {
172 MCWin64EHInstruction
&frameInst
= info
->Instructions
[info
->LastFrameInst
];
173 assert(frameInst
.getOperation() == Win64EH::UOP_SetFPReg
);
174 frame
= (frameInst
.getRegister() & 0x0F) |
175 (frameInst
.getOffset() & 0xF0);
177 streamer
.EmitIntValue(frame
, 1);
179 // Emit unwind instructions (in reverse order).
180 uint8_t numInst
= info
->Instructions
.size();
181 for (uint8_t c
= 0; c
< numInst
; ++c
) {
182 MCWin64EHInstruction inst
= info
->Instructions
.back();
183 info
->Instructions
.pop_back();
184 EmitUnwindCode(streamer
, info
->Begin
, inst
);
187 if (flags
& (Win64EH::UNW_ChainInfo
<< 3))
188 EmitRuntimeFunction(streamer
, info
->ChainedParent
);
190 ((Win64EH::UNW_TerminateHandler
|Win64EH::UNW_ExceptionHandler
) << 3))
191 streamer
.EmitValue(MCSymbolRefExpr::Create(info
->ExceptionHandler
, context
),
193 else if (numCodes
< 2) {
194 // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not
195 // a chained unwind info, if there is no handler, and if there are fewer
196 // than 2 slots used in the unwind code array, we have to pad to 8 bytes.
198 streamer
.EmitIntValue(0, 2);
200 streamer
.EmitIntValue(0, 4);
204 StringRef
MCWin64EHUnwindEmitter::GetSectionSuffix(const MCSymbol
*func
) {
205 if (!func
|| !func
->isInSection()) return "";
206 const MCSection
*section
= &func
->getSection();
207 const MCSectionCOFF
*COFFSection
;
208 if ((COFFSection
= dyn_cast
<MCSectionCOFF
>(section
))) {
209 StringRef name
= COFFSection
->getSectionName();
210 size_t dollar
= name
.find('$');
211 size_t dot
= name
.find('.', 1);
212 if (dollar
== StringRef::npos
&& dot
== StringRef::npos
)
214 if (dot
== StringRef::npos
)
215 return name
.substr(dollar
);
216 if (dollar
== StringRef::npos
|| dot
< dollar
)
217 return name
.substr(dot
);
218 return name
.substr(dollar
);
223 void MCWin64EHUnwindEmitter::EmitUnwindInfo(MCStreamer
&streamer
,
224 MCWin64EHUnwindInfo
*info
) {
225 // Switch sections (the static function above is meant to be called from
226 // here and from Emit().
227 MCContext
&context
= streamer
.getContext();
228 const TargetAsmInfo
&asmInfo
= context
.getTargetAsmInfo();
229 const MCSection
*xdataSect
=
230 asmInfo
.getWin64EHTableSection(GetSectionSuffix(info
->Function
));
231 streamer
.SwitchSection(xdataSect
);
233 llvm::EmitUnwindInfo(streamer
, info
);
236 void MCWin64EHUnwindEmitter::Emit(MCStreamer
&streamer
) {
237 MCContext
&context
= streamer
.getContext();
238 // Emit the unwind info structs first.
239 const TargetAsmInfo
&asmInfo
= context
.getTargetAsmInfo();
240 for (unsigned i
= 0; i
< streamer
.getNumW64UnwindInfos(); ++i
) {
241 MCWin64EHUnwindInfo
&info
= streamer
.getW64UnwindInfo(i
);
242 const MCSection
*xdataSect
=
243 asmInfo
.getWin64EHTableSection(GetSectionSuffix(info
.Function
));
244 streamer
.SwitchSection(xdataSect
);
245 llvm::EmitUnwindInfo(streamer
, &info
);
247 // Now emit RUNTIME_FUNCTION entries.
248 for (unsigned i
= 0; i
< streamer
.getNumW64UnwindInfos(); ++i
) {
249 MCWin64EHUnwindInfo
&info
= streamer
.getW64UnwindInfo(i
);
250 const MCSection
*pdataSect
=
251 asmInfo
.getWin64EHFuncTableSection(GetSectionSuffix(info
.Function
));
252 streamer
.SwitchSection(pdataSect
);
253 EmitRuntimeFunction(streamer
, &info
);
257 } // End of namespace llvm