LLVM  6.0.0svn
X86WinCOFFTargetStreamer.cpp
Go to the documentation of this file.
1 //===-- X86WinCOFFTargetStreamer.cpp ----------------------------*- C++ -*-===//
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 "X86MCTargetDesc.h"
11 #include "X86TargetStreamer.h"
13 #include "llvm/MC/MCCodeView.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCInstPrinter.h"
16 #include "llvm/MC/MCRegisterInfo.h"
19 
20 using namespace llvm;
21 using namespace llvm::codeview;
22 
23 namespace {
24 /// Implements Windows x86-only directives for assembly emission.
25 class X86WinCOFFAsmTargetStreamer : public X86TargetStreamer {
27  MCInstPrinter &InstPrinter;
28 
29 public:
30  X86WinCOFFAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS,
31  MCInstPrinter &InstPrinter)
32  : X86TargetStreamer(S), OS(OS), InstPrinter(InstPrinter) {}
33 
34  bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
35  SMLoc L) override;
36  bool emitFPOEndPrologue(SMLoc L) override;
37  bool emitFPOEndProc(SMLoc L) override;
38  bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;
39  bool emitFPOPushReg(unsigned Reg, SMLoc L) override;
40  bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;
41  bool emitFPOSetFrame(unsigned Reg, SMLoc L) override;
42 };
43 
44 /// Represents a single FPO directive.
45 struct FPOInstruction {
46  MCSymbol *Label;
47  enum Operation {
48  PushReg,
49  StackAlloc,
50  SetFrame,
51  } Op;
52  unsigned RegOrOffset;
53 };
54 
55 struct FPOData {
56  const MCSymbol *Function = nullptr;
57  MCSymbol *Begin = nullptr;
58  MCSymbol *PrologueEnd = nullptr;
59  MCSymbol *End = nullptr;
60  unsigned ParamsSize = 0;
61 
62  SmallVector<FPOInstruction, 5> Instructions;
63 };
64 
65 /// Implements Windows x86-only directives for object emission.
66 class X86WinCOFFTargetStreamer : public X86TargetStreamer {
67  /// Map from function symbol to its FPO data.
69 
70  /// Current FPO data created by .cv_fpo_proc.
71  std::unique_ptr<FPOData> CurFPOData;
72 
73  bool haveOpenFPOData() { return !!CurFPOData; }
74 
75  /// Diagnoses an error at L if we are not in an FPO prologue. Return true on
76  /// error.
77  bool checkInFPOPrologue(SMLoc L);
78 
79  MCSymbol *emitFPOLabel();
80 
81  MCContext &getContext() { return getStreamer().getContext(); }
82 
83 public:
84  X86WinCOFFTargetStreamer(MCStreamer &S) : X86TargetStreamer(S) {}
85 
86  bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
87  SMLoc L) override;
88  bool emitFPOEndPrologue(SMLoc L) override;
89  bool emitFPOEndProc(SMLoc L) override;
90  bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;
91  bool emitFPOPushReg(unsigned Reg, SMLoc L) override;
92  bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;
93  bool emitFPOSetFrame(unsigned Reg, SMLoc L) override;
94 };
95 } // end namespace
96 
97 bool X86WinCOFFAsmTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,
98  unsigned ParamsSize, SMLoc L) {
99  OS << "\t.cv_fpo_proc\t";
100  ProcSym->print(OS, getStreamer().getContext().getAsmInfo());
101  OS << ' ' << ParamsSize << '\n';
102  return false;
103 }
104 
105 bool X86WinCOFFAsmTargetStreamer::emitFPOEndPrologue(SMLoc L) {
106  OS << "\t.cv_fpo_endprologue\n";
107  return false;
108 }
109 
110 bool X86WinCOFFAsmTargetStreamer::emitFPOEndProc(SMLoc L) {
111  OS << "\t.cv_fpo_endproc\n";
112  return false;
113 }
114 
115 bool X86WinCOFFAsmTargetStreamer::emitFPOData(const MCSymbol *ProcSym,
116  SMLoc L) {
117  OS << "\t.cv_fpo_data\t";
118  ProcSym->print(OS, getStreamer().getContext().getAsmInfo());
119  OS << '\n';
120  return false;
121 }
122 
123 bool X86WinCOFFAsmTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) {
124  OS << "\t.cv_fpo_pushreg\t";
125  InstPrinter.printRegName(OS, Reg);
126  OS << '\n';
127  return false;
128 }
129 
130 bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc,
131  SMLoc L) {
132  OS << "\t.cv_fpo_stackalloc\t" << StackAlloc << '\n';
133  return false;
134 }
135 
136 bool X86WinCOFFAsmTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) {
137  OS << "\t.cv_fpo_setframe\t";
138  InstPrinter.printRegName(OS, Reg);
139  OS << '\n';
140  return false;
141 }
142 
143 bool X86WinCOFFTargetStreamer::checkInFPOPrologue(SMLoc L) {
144  if (!haveOpenFPOData() || CurFPOData->PrologueEnd) {
145  getContext().reportError(
146  L,
147  "directive must appear between .cv_fpo_proc and .cv_fpo_endprologue");
148  return true;
149  }
150  return false;
151 }
152 
153 MCSymbol *X86WinCOFFTargetStreamer::emitFPOLabel() {
154  MCSymbol *Label = getContext().createTempSymbol("cfi", true);
155  getStreamer().EmitLabel(Label);
156  return Label;
157 }
158 
159 bool X86WinCOFFTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,
160  unsigned ParamsSize, SMLoc L) {
161  if (haveOpenFPOData()) {
162  getContext().reportError(
163  L, "opening new .cv_fpo_proc before closing previous frame");
164  return true;
165  }
166  CurFPOData = llvm::make_unique<FPOData>();
167  CurFPOData->Function = ProcSym;
168  CurFPOData->Begin = emitFPOLabel();
169  CurFPOData->ParamsSize = ParamsSize;
170  return false;
171 }
172 
173 bool X86WinCOFFTargetStreamer::emitFPOEndProc(SMLoc L) {
174  if (!haveOpenFPOData()) {
175  getContext().reportError(L, ".cv_fpo_endproc must appear after .cv_proc");
176  return true;
177  }
178  if (!CurFPOData->PrologueEnd) {
179  // Complain if there were prologue setup instructions but no end prologue.
180  if (!CurFPOData->Instructions.empty()) {
181  getContext().reportError(L, "missing .cv_fpo_endprologue");
182  CurFPOData->Instructions.clear();
183  }
184 
185  // Claim there is a zero-length prologue to make the label math work out
186  // later.
187  CurFPOData->PrologueEnd = CurFPOData->Begin;
188  }
189 
190  CurFPOData->End = emitFPOLabel();
191  const MCSymbol *Fn = CurFPOData->Function;
192  AllFPOData.insert({Fn, std::move(CurFPOData)});
193  return false;
194 }
195 
196 bool X86WinCOFFTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) {
197  if (checkInFPOPrologue(L))
198  return true;
199  FPOInstruction Inst;
200  Inst.Label = emitFPOLabel();
201  Inst.Op = FPOInstruction::SetFrame;
202  Inst.RegOrOffset = Reg;
203  CurFPOData->Instructions.push_back(Inst);
204  return false;
205 }
206 
207 bool X86WinCOFFTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) {
208  if (checkInFPOPrologue(L))
209  return true;
210  FPOInstruction Inst;
211  Inst.Label = emitFPOLabel();
212  Inst.Op = FPOInstruction::PushReg;
213  Inst.RegOrOffset = Reg;
214  CurFPOData->Instructions.push_back(Inst);
215  return false;
216 }
217 
218 bool X86WinCOFFTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) {
219  if (checkInFPOPrologue(L))
220  return true;
221  FPOInstruction Inst;
222  Inst.Label = emitFPOLabel();
223  Inst.Op = FPOInstruction::StackAlloc;
224  Inst.RegOrOffset = StackAlloc;
225  CurFPOData->Instructions.push_back(Inst);
226  return false;
227 }
228 
229 bool X86WinCOFFTargetStreamer::emitFPOEndPrologue(SMLoc L) {
230  if (checkInFPOPrologue(L))
231  return true;
232  CurFPOData->PrologueEnd = emitFPOLabel();
233  return false;
234 }
235 
236 namespace {
237 struct RegSaveOffset {
238  RegSaveOffset(unsigned Reg, unsigned Offset) : Reg(Reg), Offset(Offset) {}
239 
240  unsigned Reg = 0;
241  unsigned Offset = 0;
242 };
243 
244 struct FPOStateMachine {
245  explicit FPOStateMachine(const FPOData *FPO) : FPO(FPO) {}
246 
247  const FPOData *FPO = nullptr;
248  unsigned FrameReg = 0;
249  unsigned FrameRegOff = 0;
250  unsigned CurOffset = 0;
251  unsigned LocalSize = 0;
252  unsigned SavedRegSize = 0;
253  unsigned Flags = 0; // FIXME: Set HasSEH / HasEH.
254 
255  SmallString<128> FrameFunc;
256 
257  SmallVector<RegSaveOffset, 4> RegSaveOffsets;
258 
259  void emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label);
260 };
261 } // end namespace
262 
263 static Printable printFPOReg(const MCRegisterInfo *MRI, unsigned LLVMReg) {
264  return Printable([MRI, LLVMReg](raw_ostream &OS) {
265  switch (LLVMReg) {
266  // MSVC only seems to emit symbolic register names for EIP, EBP, and ESP,
267  // but the format seems to support more than that, so we emit them.
268  case X86::EAX: OS << "$eax"; break;
269  case X86::EBX: OS << "$ebx"; break;
270  case X86::ECX: OS << "$ecx"; break;
271  case X86::EDX: OS << "$edx"; break;
272  case X86::EDI: OS << "$edi"; break;
273  case X86::ESI: OS << "$esi"; break;
274  case X86::ESP: OS << "$esp"; break;
275  case X86::EBP: OS << "$ebp"; break;
276  case X86::EIP: OS << "$eip"; break;
277  // Otherwise, get the codeview register number and print $N.
278  default:
279  OS << '$' << MRI->getCodeViewRegNum(LLVMReg);
280  break;
281  }
282  });
283 }
284 
285 void FPOStateMachine::emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label) {
286  unsigned CurFlags = Flags;
287  if (Label == FPO->Begin)
288  CurFlags |= FrameData::IsFunctionStart;
289 
290  // Compute the new FrameFunc string.
291  FrameFunc.clear();
292  raw_svector_ostream FuncOS(FrameFunc);
294  if (FrameReg) {
295  // CFA is FrameReg + FrameRegOff.
296  FuncOS << "$T0 " << printFPOReg(MRI, FrameReg) << " " << FrameRegOff
297  << " + = ";
298  } else {
299  // The address of return address is ESP + CurOffset, but we use .raSearch to
300  // match MSVC. This seems to ask the debugger to subtract some combination
301  // of LocalSize and SavedRegSize from ESP and grovel around in that memory
302  // to find the address of a plausible return address.
303  FuncOS << "$T0 .raSearch = ";
304  }
305 
306  // Caller's $eip should be dereferenced CFA, and $esp should be CFA plus 4.
307  FuncOS << "$eip $T0 ^ = $esp $T0 4 + = ";
308 
309  // Each saved register is stored at an unchanging negative CFA offset.
310  for (RegSaveOffset RO : RegSaveOffsets)
311  FuncOS << printFPOReg(MRI, RO.Reg) << " $T0 " << RO.Offset << " - ^ = ";
312 
313  // Add it to the CV string table.
314  CodeViewContext &CVCtx = OS.getContext().getCVContext();
315  unsigned FrameFuncStrTabOff = CVCtx.addToStringTable(FuncOS.str()).second;
316 
317  // MSVC has only ever been observed to emit a MaxStackSize of zero.
318  unsigned MaxStackSize = 0;
319 
320  // The FrameData record format is:
321  // ulittle32_t RvaStart;
322  // ulittle32_t CodeSize;
323  // ulittle32_t LocalSize;
324  // ulittle32_t ParamsSize;
325  // ulittle32_t MaxStackSize;
326  // ulittle32_t FrameFunc; // String table offset
327  // ulittle16_t PrologSize;
328  // ulittle16_t SavedRegsSize;
329  // ulittle32_t Flags;
330 
331  OS.emitAbsoluteSymbolDiff(Label, FPO->Begin, 4); // RvaStart
332  OS.emitAbsoluteSymbolDiff(FPO->End, Label, 4); // CodeSize
333  OS.EmitIntValue(LocalSize, 4);
334  OS.EmitIntValue(FPO->ParamsSize, 4);
335  OS.EmitIntValue(MaxStackSize, 4);
336  OS.EmitIntValue(FrameFuncStrTabOff, 4); // FrameFunc
337  OS.emitAbsoluteSymbolDiff(FPO->PrologueEnd, Label, 2);
338  OS.EmitIntValue(SavedRegSize, 2);
339  OS.EmitIntValue(CurFlags, 4);
340 }
341 
342 /// Compute and emit the real CodeView FrameData subsection.
343 bool X86WinCOFFTargetStreamer::emitFPOData(const MCSymbol *ProcSym, SMLoc L) {
344  MCStreamer &OS = getStreamer();
345  MCContext &Ctx = OS.getContext();
346 
347  auto I = AllFPOData.find(ProcSym);
348  if (I == AllFPOData.end()) {
349  Ctx.reportError(L, Twine("no FPO data found for symbol ") +
350  ProcSym->getName());
351  return true;
352  }
353  const FPOData *FPO = I->second.get();
354  assert(FPO->Begin && FPO->End && FPO->PrologueEnd && "missing FPO label");
355 
356  MCSymbol *FrameBegin = Ctx.createTempSymbol(),
357  *FrameEnd = Ctx.createTempSymbol();
358 
360  OS.emitAbsoluteSymbolDiff(FrameEnd, FrameBegin, 4);
361  OS.EmitLabel(FrameBegin);
362 
363  // Start with the RVA of the function in question.
364  OS.EmitValue(MCSymbolRefExpr::create(FPO->Function,
366  4);
367 
368  // Emit a sequence of FrameData records.
369  FPOStateMachine FSM(FPO);
370 
371  FSM.emitFrameDataRecord(OS, FPO->Begin);
372  for (const FPOInstruction &Inst : FPO->Instructions) {
373  switch (Inst.Op) {
374  case FPOInstruction::PushReg:
375  FSM.CurOffset += 4;
376  FSM.SavedRegSize += 4;
377  FSM.RegSaveOffsets.push_back({Inst.RegOrOffset, FSM.CurOffset});
378  break;
379  case FPOInstruction::SetFrame:
380  FSM.FrameReg = Inst.RegOrOffset;
381  FSM.FrameRegOff = FSM.CurOffset;
382  break;
383  case FPOInstruction::StackAlloc:
384  FSM.CurOffset += Inst.RegOrOffset;
385  FSM.LocalSize += Inst.RegOrOffset;
386  // No need to emit FrameData for stack allocations with a frame pointer.
387  if (FSM.FrameReg)
388  continue;
389  break;
390  }
391  FSM.emitFrameDataRecord(OS, Inst.Label);
392  }
393 
394  OS.EmitValueToAlignment(4, 0);
395  OS.EmitLabel(FrameEnd);
396  return false;
397 }
398 
401  MCInstPrinter *InstPrinter,
402  bool IsVerboseAsm) {
403  // FIXME: This makes it so we textually assemble COFF directives on ELF.
404  // That's kind of nonsensical.
405  return new X86WinCOFFAsmTargetStreamer(S, OS, *InstPrinter);
406 }
407 
410  // No need to register a target streamer.
411  if (!STI.getTargetTriple().isOSBinFormatCOFF())
412  return nullptr;
413  // Registers itself to the MCStreamer.
414  return new X86WinCOFFTargetStreamer(S);
415 }
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
Definition: MCExpr.h:305
Compute iterated dominance frontiers using a linear time algorithm.
Definition: AllocatorList.h:24
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:42
formatted_raw_ostream - A raw_ostream that wraps another one and keeps track of line and column posit...
MCTargetStreamer * createX86ObjectTargetStreamer(MCStreamer &OS, const MCSubtargetInfo &STI)
Implements X86-only directives for object files.
Target specific streamer interface.
Definition: MCStreamer.h:80
std::pair< StringRef, unsigned > addToStringTable(StringRef S)
Add something to the string table.
Definition: MCCodeView.cpp:133
A raw_ostream that writes to an SmallVector or SmallString.
Definition: raw_ostream.h:489
unsigned second
const Triple & getTargetTriple() const
getTargetTriple - Return the target triple string.
MCContext & getContext() const
Definition: MCStreamer.h:234
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
Reg
All possible values of the reg field in the ModR/M byte.
Context object for machine code objects.
Definition: MCContext.h:59
virtual void EmitIntValue(uint64_t Value, unsigned Size)
Special case of EmitValue that avoids the client having to pass in a MCExpr for constant integers...
Definition: MCStreamer.cpp:88
void EmitValue(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc())
Definition: MCStreamer.cpp:123
MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...
Streaming machine code generation interface.
Definition: MCStreamer.h:169
MCSymbol * createTempSymbol(bool CanBeUnnamed=true)
Create and return a new assembler temporary symbol with a unique but unspecified name.
Definition: MCContext.cpp:215
unsigned const MachineRegisterInfo * MRI
bool isOSBinFormatCOFF() const
Tests whether the OS uses the COFF binary format.
Definition: Triple.h:593
static Printable printFPOReg(const MCRegisterInfo *MRI, unsigned LLVMReg)
virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value=0, unsigned ValueSize=1, unsigned MaxBytesToEmit=0)
Emit some number of copies of Value until the byte alignment ByteAlignment is reached.
Definition: MCStreamer.cpp:925
static const unsigned End
void reportError(SMLoc L, const Twine &Msg)
Definition: MCContext.cpp:570
MCTargetStreamer * createX86AsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS, MCInstPrinter *InstPrint, bool isVerboseAsm)
Implements X86-only directives for assembly emission.
virtual void emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size)
Emit the absolute difference between two symbols.
Definition: MCStreamer.cpp:871
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:864
StringRef str()
Return a StringRef for the vector contents.
Definition: raw_ostream.h:514
X86 target streamer implementing x86-only assembly directives.
int getCodeViewRegNum(unsigned RegNum) const
Map a target register to an equivalent CodeView register number.
This is an instance of a target assembly language printer that converts an MCInst to valid target ass...
Definition: MCInstPrinter.h:41
#define I(x, y, z)
Definition: MD5.cpp:58
MCSubtargetInfo - Generic base class for all target subtargets.
StringRef getName() const
getName - Get the symbol name.
Definition: MCSymbol.h:203
CodeViewContext & getCVContext()
Definition: MCContext.cpp:560
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
const MCRegisterInfo * getRegisterInfo() const
Definition: MCContext.h:285
virtual void EmitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc())
Emit a label for Symbol into the current section.
Definition: MCStreamer.cpp:300
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:44
Simple wrapper around std::function<void(raw_ostream&)>.
Definition: Printable.h:38
Represents a location in source code.
Definition: SMLoc.h:24
void print(raw_ostream &OS, const MCAsmInfo *MAI) const
print - Print the value to the stream OS.
Definition: MCSymbol.cpp:59
Holds state from .cv_file and .cv_loc directives for later emission.
Definition: MCCodeView.h:158