[ms] [llvm-ml] Add basic support for SEH, including PROC FRAME
authorEric Astor <epastor@google.com>
Mon, 14 Sep 2020 18:32:33 +0000 (14:32 -0400)
committerEric Astor <epastor@google.com>
Mon, 14 Sep 2020 18:32:55 +0000 (14:32 -0400)
Add basic support for SEH, including PROC FRAME

Reviewed By: thakis

Differential Revision: https://reviews.llvm.org/D86948

llvm/lib/MC/MCParser/COFFMasmParser.cpp
llvm/lib/MC/MCParser/MasmParser.cpp
llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
llvm/test/tools/llvm-ml/proc.test [new file with mode: 0644]
llvm/test/tools/llvm-ml/proc_frame.test [new file with mode: 0644]

index b7c48e9..532ded0 100644 (file)
@@ -53,6 +53,9 @@ class COFFMasmParser : public MCAsmParserExtension {
   bool ParseDirectiveSegmentEnd(StringRef, SMLoc);
   bool ParseDirectiveIncludelib(StringRef, SMLoc);
 
+  bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
+  bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
+
   bool IgnoreDirective(StringRef, SMLoc) {
     while (!getLexer().is(AsmToken::EndOfStatement)) {
       Lex();
@@ -65,13 +68,10 @@ class COFFMasmParser : public MCAsmParserExtension {
     MCAsmParserExtension::Initialize(Parser);
 
     // x64 directives
-    // .allocstack
-    // .endprolog
-    // .pushframe
-    // .pushreg
-    // .savereg
-    // .savexmm128
-    // .setframe
+    addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveAllocStack>(
+        ".allocstack");
+    addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveEndProlog>(
+        ".endprolog");
 
     // Code label directives
     // label
@@ -92,16 +92,12 @@ class COFFMasmParser : public MCAsmParserExtension {
 
     // Data allocation directives
     // align
-    // byte/sbyte
-    // dword/sdword
     // even
-    // fword
-    // qword
-    // real4
-    // real8
+    // mmword
     // real10
     // tbyte
-    // word/sword
+    // xmmword
+    // ymmword
 
     // Listing control directives
     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".cref");
@@ -133,14 +129,11 @@ class COFFMasmParser : public MCAsmParserExtension {
     // .fpo
     addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>(
         "includelib");
-    // mmword
     // option
     // popcontext
     // pushcontext
     // .radix
     // .safeseh
-    // xmmword
-    // ymmword
 
     // Procedure directives
     addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>("endp");
@@ -148,7 +141,7 @@ class COFFMasmParser : public MCAsmParserExtension {
     addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>("proc");
     // proto
 
-    // Processor directives
+    // Processor directives; all ignored
     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386");
     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386P");
     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".387");
@@ -202,11 +195,8 @@ class COFFMasmParser : public MCAsmParserExtension {
     // substr (equivalent to <name> TEXTEQU @SubStr(<params>))
 
     // Structure and record directives
-    // ends
     // record
-    // struct
     // typedef
-    // union
   }
 
   bool ParseSectionDirectiveCode(StringRef, SMLoc) {
@@ -234,6 +224,7 @@ class COFFMasmParser : public MCAsmParserExtension {
   }
 
   StringRef CurrentProcedure;
+  bool CurrentProcedureFramed;
 
 public:
   COFFMasmParser() = default;
@@ -361,8 +352,17 @@ bool COFFMasmParser::ParseDirectiveProc(StringRef Directive, SMLoc Loc) {
   getStreamer().EmitCOFFSymbolType(0x20);
   getStreamer().EndCOFFSymbolDef();
 
+  bool Framed = false;
+  if (getLexer().is(AsmToken::Identifier) &&
+      getTok().getString().equals_lower("frame")) {
+    Lex();
+    Framed = true;
+    getStreamer().EmitWinCFIStartProc(Sym, Loc);
+  }
   getStreamer().emitLabel(Sym, Loc);
+
   CurrentProcedure = Label;
+  CurrentProcedureFramed = Framed;
   return false;
 }
 bool COFFMasmParser::ParseDirectiveEndProc(StringRef Directive, SMLoc Loc) {
@@ -376,6 +376,30 @@ bool COFFMasmParser::ParseDirectiveEndProc(StringRef Directive, SMLoc Loc) {
   else if (CurrentProcedure != Label)
     return Error(LabelLoc, "endp does not match current procedure '" +
                                CurrentProcedure + "'");
+
+  if (CurrentProcedureFramed) {
+    getStreamer().EmitWinCFIEndProc(Loc);
+  }
+  CurrentProcedure = "";
+  CurrentProcedureFramed = false;
+  return false;
+}
+
+bool COFFMasmParser::ParseSEHDirectiveAllocStack(StringRef Directive,
+                                                 SMLoc Loc) {
+  int64_t Size;
+  SMLoc SizeLoc = getTok().getLoc();
+  if (getParser().parseAbsoluteExpression(Size))
+    return Error(SizeLoc, "expected integer size");
+  if (Size % 8 != 0)
+    return Error(SizeLoc, "stack size must be a multiple of 8");
+  getStreamer().EmitWinCFIAllocStack(static_cast<unsigned>(Size), Loc);
+  return false;
+}
+
+bool COFFMasmParser::ParseSEHDirectiveEndProlog(StringRef Directive,
+                                                SMLoc Loc) {
+  getStreamer().EmitWinCFIEndProlog(Loc);
   return false;
 }
 
index cc82ffb..ca9b2df 100644 (file)
@@ -726,7 +726,12 @@ private:
     DK_STRUCT,
     DK_UNION,
     DK_ENDS,
-    DK_END
+    DK_END,
+    DK_PUSHFRAME,
+    DK_PUSHREG,
+    DK_SAVEREG,
+    DK_SAVEXMM128,
+    DK_SETFRAME,
   };
 
   /// Maps directive name --> DirectiveKind enum, for directives parsed by this
@@ -6333,6 +6338,11 @@ void MasmParser::initializeDirectiveKindMap() {
   DirectiveKindMap[".erridni"] = DK_ERRIDNI;
   DirectiveKindMap[".erre"] = DK_ERRE;
   DirectiveKindMap[".errnz"] = DK_ERRNZ;
+  DirectiveKindMap[".pushframe"] = DK_PUSHFRAME;
+  DirectiveKindMap[".pushreg"] = DK_PUSHREG;
+  DirectiveKindMap[".savereg"] = DK_SAVEREG;
+  DirectiveKindMap[".savexmm128"] = DK_SAVEXMM128;
+  DirectiveKindMap[".setframe"] = DK_SETFRAME;
   // DirectiveKindMap[".altmacro"] = DK_ALTMACRO;
   // DirectiveKindMap[".noaltmacro"] = DK_NOALTMACRO;
   DirectiveKindMap["db"] = DK_DB;
index 361a6c0..3270932 100644 (file)
@@ -4172,15 +4172,20 @@ bool X86AsmParser::ParseDirective(AsmToken DirectiveID) {
     return parseDirectiveFPOEndPrologue(DirectiveID.getLoc());
   else if (IDVal == ".cv_fpo_endproc")
     return parseDirectiveFPOEndProc(DirectiveID.getLoc());
-  else if (IDVal == ".seh_pushreg")
+  else if (IDVal == ".seh_pushreg" ||
+           (Parser.isParsingMasm() && IDVal.equals_lower(".pushreg")))
     return parseDirectiveSEHPushReg(DirectiveID.getLoc());
-  else if (IDVal == ".seh_setframe")
+  else if (IDVal == ".seh_setframe" ||
+           (Parser.isParsingMasm() && IDVal.equals_lower(".setframe")))
     return parseDirectiveSEHSetFrame(DirectiveID.getLoc());
-  else if (IDVal == ".seh_savereg")
+  else if (IDVal == ".seh_savereg" ||
+           (Parser.isParsingMasm() && IDVal.equals_lower(".savereg")))
     return parseDirectiveSEHSaveReg(DirectiveID.getLoc());
-  else if (IDVal == ".seh_savexmm")
+  else if (IDVal == ".seh_savexmm" ||
+           (Parser.isParsingMasm() && IDVal.equals_lower(".savexmm128")))
     return parseDirectiveSEHSaveXMM(DirectiveID.getLoc());
-  else if (IDVal == ".seh_pushframe")
+  else if (IDVal == ".seh_pushframe" ||
+           (Parser.isParsingMasm() && IDVal.equals_lower(".pushframe")))
     return parseDirectiveSEHPushFrame(DirectiveID.getLoc());
 
   return true;
diff --git a/llvm/test/tools/llvm-ml/proc.test b/llvm/test/tools/llvm-ml/proc.test
new file mode 100644 (file)
index 0000000..ad117f7
--- /dev/null
@@ -0,0 +1,18 @@
+# RUN: llvm-ml -m32 -filetype=asm %s | FileCheck %s
+# RUN: llvm-ml -m64 -filetype=asm %s | FileCheck %s
+
+.code
+
+t1 PROC
+  ret
+t1 ENDP
+
+; CHECK: .def t1
+; CHECK-NEXT: .scl 2
+; CHECK-NEXT: .type 32
+; CHECK-NEXT: .endef
+
+; CHECK: t1:
+; CHECK: ret
+
+END
diff --git a/llvm/test/tools/llvm-ml/proc_frame.test b/llvm/test/tools/llvm-ml/proc_frame.test
new file mode 100644 (file)
index 0000000..3bf1c3a
--- /dev/null
@@ -0,0 +1,34 @@
+# RUN: llvm-ml -m64 -filetype=asm %s | FileCheck %s
+
+.code
+
+t1 PROC FRAME
+  push rbp
+  .pushreg rbp
+  mov rbp, rsp
+  .setframe rbp, 0
+  pushfq
+  .allocstack 8
+  .endprolog
+  ret
+t1 ENDP
+
+; CHECK: .def t1
+; CHECK-NEXT: .scl 2
+; CHECK-NEXT: .type 32
+; CHECK-NEXT: .endef
+
+; CHECK: .seh_proc t1
+
+; CHECK: t1:
+; CHECK: push rbp
+; CHECK: .seh_pushreg rbp
+; CHECK: mov rbp, rsp
+; CHECK: .seh_setframe rbp, 0
+; CHECK: pushfq
+; CHECK: .seh_stackalloc 8
+; CHECK: .seh_endprologue
+; CHECK: ret
+; CHECK: .seh_endproc
+
+END