1 //===- COFFMasmParser.cpp - COFF MASM Assembly Parser ---------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/ADT/StringRef.h" 10 #include "llvm/ADT/Triple.h" 11 #include "llvm/ADT/Twine.h" 12 #include "llvm/BinaryFormat/COFF.h" 13 #include "llvm/MC/MCContext.h" 14 #include "llvm/MC/MCDirectives.h" 15 #include "llvm/MC/MCObjectFileInfo.h" 16 #include "llvm/MC/MCParser/MCAsmLexer.h" 17 #include "llvm/MC/MCParser/MCAsmParserExtension.h" 18 #include "llvm/MC/MCParser/MCAsmParserUtils.h" 19 #include "llvm/MC/MCParser/MCTargetAsmParser.h" 20 #include "llvm/MC/MCRegisterInfo.h" 21 #include "llvm/MC/MCSectionCOFF.h" 22 #include "llvm/MC/MCStreamer.h" 23 #include "llvm/MC/MCSymbolCOFF.h" 24 #include "llvm/MC/SectionKind.h" 25 #include "llvm/Support/SMLoc.h" 26 #include <cassert> 27 #include <cstdint> 28 #include <limits> 29 #include <utility> 30 31 using namespace llvm; 32 33 namespace { 34 35 class COFFMasmParser : public MCAsmParserExtension { 36 template <bool (COFFMasmParser::*HandlerMethod)(StringRef, SMLoc)> 37 void addDirectiveHandler(StringRef Directive) { 38 MCAsmParser::ExtensionDirectiveHandler Handler = 39 std::make_pair(this, HandleDirective<COFFMasmParser, HandlerMethod>); 40 getParser().addDirectiveHandler(Directive, Handler); 41 } 42 43 bool ParseSectionSwitch(StringRef Section, unsigned Characteristics, 44 SectionKind Kind); 45 46 bool ParseSectionSwitch(StringRef Section, unsigned Characteristics, 47 SectionKind Kind, StringRef COMDATSymName, 48 COFF::COMDATType Type); 49 50 bool ParseDirectiveProc(StringRef, SMLoc); 51 bool ParseDirectiveEndProc(StringRef, SMLoc); 52 bool ParseDirectiveSegment(StringRef, SMLoc); 53 bool ParseDirectiveSegmentEnd(StringRef, SMLoc); 54 bool ParseDirectiveIncludelib(StringRef, SMLoc); 55 56 bool ParseDirectiveAlias(StringRef, SMLoc); 57 58 bool ParseSEHDirectiveAllocStack(StringRef, SMLoc); 59 bool ParseSEHDirectiveEndProlog(StringRef, SMLoc); 60 61 bool IgnoreDirective(StringRef, SMLoc) { 62 while (!getLexer().is(AsmToken::EndOfStatement)) { 63 Lex(); 64 } 65 return false; 66 } 67 68 void Initialize(MCAsmParser &Parser) override { 69 // Call the base implementation. 70 MCAsmParserExtension::Initialize(Parser); 71 72 // x64 directives 73 addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveAllocStack>( 74 ".allocstack"); 75 addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveEndProlog>( 76 ".endprolog"); 77 78 // Code label directives 79 // label 80 // org 81 82 // Conditional control flow directives 83 // .break 84 // .continue 85 // .else 86 // .elseif 87 // .endif 88 // .endw 89 // .if 90 // .repeat 91 // .until 92 // .untilcxz 93 // .while 94 95 // Data allocation directives 96 // align 97 // even 98 // mmword 99 // tbyte 100 // xmmword 101 // ymmword 102 103 // Listing control directives 104 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".cref"); 105 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".list"); 106 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listall"); 107 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listif"); 108 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacro"); 109 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacroall"); 110 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nocref"); 111 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolist"); 112 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistif"); 113 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistmacro"); 114 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("page"); 115 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("subtitle"); 116 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".tfcond"); 117 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("title"); 118 119 // Macro directives 120 // goto 121 122 // Miscellaneous directives 123 addDirectiveHandler<&COFFMasmParser::ParseDirectiveAlias>("alias"); 124 // assume 125 // .fpo 126 addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>( 127 "includelib"); 128 // option 129 // popcontext 130 // pushcontext 131 // .safeseh 132 133 // Procedure directives 134 addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>("endp"); 135 // invoke (32-bit only) 136 addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>("proc"); 137 // proto 138 139 // Processor directives; all ignored 140 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386"); 141 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386P"); 142 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".387"); 143 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486"); 144 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486P"); 145 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586"); 146 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586P"); 147 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686"); 148 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686P"); 149 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".k3d"); 150 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".mmx"); 151 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".xmm"); 152 153 // Scope directives 154 // comm 155 // externdef 156 157 // Segment directives 158 // .alpha (32-bit only, order segments alphabetically) 159 // .dosseg (32-bit only, order segments in DOS convention) 160 // .seq (32-bit only, order segments sequentially) 161 addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegmentEnd>("ends"); 162 // group (32-bit only) 163 addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegment>("segment"); 164 165 // Simplified segment directives 166 addDirectiveHandler<&COFFMasmParser::ParseSectionDirectiveCode>(".code"); 167 // .const 168 addDirectiveHandler< 169 &COFFMasmParser::ParseSectionDirectiveInitializedData>(".data"); 170 addDirectiveHandler< 171 &COFFMasmParser::ParseSectionDirectiveUninitializedData>(".data?"); 172 // .exit 173 // .fardata 174 // .fardata? 175 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".model"); 176 // .stack 177 // .startup 178 179 // String directives, written <name> <directive> <params> 180 // catstr (equivalent to <name> TEXTEQU <params>) 181 // instr (equivalent to <name> = @InStr(<params>)) 182 // sizestr (equivalent to <name> = @SizeStr(<params>)) 183 // substr (equivalent to <name> TEXTEQU @SubStr(<params>)) 184 185 // Structure and record directives 186 // record 187 // typedef 188 } 189 190 bool ParseSectionDirectiveCode(StringRef, SMLoc) { 191 return ParseSectionSwitch(".text", 192 COFF::IMAGE_SCN_CNT_CODE 193 | COFF::IMAGE_SCN_MEM_EXECUTE 194 | COFF::IMAGE_SCN_MEM_READ, 195 SectionKind::getText()); 196 } 197 198 bool ParseSectionDirectiveInitializedData(StringRef, SMLoc) { 199 return ParseSectionSwitch(".data", 200 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA 201 | COFF::IMAGE_SCN_MEM_READ 202 | COFF::IMAGE_SCN_MEM_WRITE, 203 SectionKind::getData()); 204 } 205 206 bool ParseSectionDirectiveUninitializedData(StringRef, SMLoc) { 207 return ParseSectionSwitch(".bss", 208 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA 209 | COFF::IMAGE_SCN_MEM_READ 210 | COFF::IMAGE_SCN_MEM_WRITE, 211 SectionKind::getBSS()); 212 } 213 214 StringRef CurrentProcedure; 215 bool CurrentProcedureFramed; 216 217 public: 218 COFFMasmParser() = default; 219 }; 220 221 } // end anonymous namespace. 222 223 static SectionKind computeSectionKind(unsigned Flags) { 224 if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE) 225 return SectionKind::getText(); 226 if (Flags & COFF::IMAGE_SCN_MEM_READ && 227 (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0) 228 return SectionKind::getReadOnly(); 229 return SectionKind::getData(); 230 } 231 232 bool COFFMasmParser::ParseSectionSwitch(StringRef Section, 233 unsigned Characteristics, 234 SectionKind Kind) { 235 return ParseSectionSwitch(Section, Characteristics, Kind, "", 236 (COFF::COMDATType)0); 237 } 238 239 bool COFFMasmParser::ParseSectionSwitch(StringRef Section, 240 unsigned Characteristics, 241 SectionKind Kind, 242 StringRef COMDATSymName, 243 COFF::COMDATType Type) { 244 if (getLexer().isNot(AsmToken::EndOfStatement)) 245 return TokError("unexpected token in section switching directive"); 246 Lex(); 247 248 getStreamer().SwitchSection(getContext().getCOFFSection( 249 Section, Characteristics, Kind, COMDATSymName, Type)); 250 251 return false; 252 } 253 254 bool COFFMasmParser::ParseDirectiveSegment(StringRef Directive, SMLoc Loc) { 255 StringRef SegmentName; 256 if (!getLexer().is(AsmToken::Identifier)) 257 return TokError("expected identifier in directive"); 258 SegmentName = getTok().getIdentifier(); 259 Lex(); 260 261 StringRef SectionName = SegmentName; 262 SmallVector<char, 247> SectionNameVector; 263 unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | 264 COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE; 265 if (SegmentName == "_TEXT" || SegmentName.startswith("_TEXT$")) { 266 if (SegmentName.size() == 5) { 267 SectionName = ".text"; 268 } else { 269 SectionName = 270 (".text$" + SegmentName.substr(6)).toStringRef(SectionNameVector); 271 } 272 Flags = COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE | 273 COFF::IMAGE_SCN_MEM_READ; 274 } 275 SectionKind Kind = computeSectionKind(Flags); 276 getStreamer().SwitchSection(getContext().getCOFFSection( 277 SectionName, Flags, Kind, "", (COFF::COMDATType)(0))); 278 return false; 279 } 280 281 /// ParseDirectiveSegmentEnd 282 /// ::= identifier "ends" 283 bool COFFMasmParser::ParseDirectiveSegmentEnd(StringRef Directive, SMLoc Loc) { 284 StringRef SegmentName; 285 if (!getLexer().is(AsmToken::Identifier)) 286 return TokError("expected identifier in directive"); 287 SegmentName = getTok().getIdentifier(); 288 289 // Ignore; no action necessary. 290 Lex(); 291 return false; 292 } 293 294 /// ParseDirectiveIncludelib 295 /// ::= "includelib" identifier 296 bool COFFMasmParser::ParseDirectiveIncludelib(StringRef Directive, SMLoc Loc) { 297 StringRef Lib; 298 if (getParser().parseIdentifier(Lib)) 299 return TokError("expected identifier in includelib directive"); 300 301 unsigned Flags = COFF::IMAGE_SCN_MEM_PRELOAD | COFF::IMAGE_SCN_MEM_16BIT; 302 SectionKind Kind = computeSectionKind(Flags); 303 getStreamer().PushSection(); 304 getStreamer().SwitchSection(getContext().getCOFFSection( 305 ".drectve", Flags, Kind, "", (COFF::COMDATType)(0))); 306 getStreamer().emitBytes("/DEFAULTLIB:"); 307 getStreamer().emitBytes(Lib); 308 getStreamer().emitBytes(" "); 309 getStreamer().PopSection(); 310 return false; 311 } 312 313 /// ParseDirectiveProc 314 /// TODO(epastor): Implement parameters and other attributes. 315 /// ::= label "proc" [[distance]] 316 /// statements 317 /// label "endproc" 318 bool COFFMasmParser::ParseDirectiveProc(StringRef Directive, SMLoc Loc) { 319 StringRef Label; 320 if (getParser().parseIdentifier(Label)) 321 return Error(Loc, "expected identifier for procedure"); 322 if (getLexer().is(AsmToken::Identifier)) { 323 StringRef nextVal = getTok().getString(); 324 SMLoc nextLoc = getTok().getLoc(); 325 if (nextVal.equals_lower("far")) { 326 // TODO(epastor): Handle far procedure definitions. 327 Lex(); 328 return Error(nextLoc, "far procedure definitions not yet supported"); 329 } else if (nextVal.equals_lower("near")) { 330 Lex(); 331 nextVal = getTok().getString(); 332 nextLoc = getTok().getLoc(); 333 } 334 } 335 MCSymbolCOFF *Sym = cast<MCSymbolCOFF>(getContext().getOrCreateSymbol(Label)); 336 337 // Define symbol as simple external function 338 Sym->setExternal(true); 339 Sym->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT); 340 341 bool Framed = false; 342 if (getLexer().is(AsmToken::Identifier) && 343 getTok().getString().equals_lower("frame")) { 344 Lex(); 345 Framed = true; 346 getStreamer().EmitWinCFIStartProc(Sym, Loc); 347 } 348 getStreamer().emitLabel(Sym, Loc); 349 350 CurrentProcedure = Label; 351 CurrentProcedureFramed = Framed; 352 return false; 353 } 354 bool COFFMasmParser::ParseDirectiveEndProc(StringRef Directive, SMLoc Loc) { 355 StringRef Label; 356 SMLoc LabelLoc = getTok().getLoc(); 357 if (getParser().parseIdentifier(Label)) 358 return Error(LabelLoc, "expected identifier for procedure end"); 359 360 if (CurrentProcedure.empty()) 361 return Error(Loc, "endp outside of procedure block"); 362 else if (CurrentProcedure != Label) 363 return Error(LabelLoc, "endp does not match current procedure '" + 364 CurrentProcedure + "'"); 365 366 if (CurrentProcedureFramed) { 367 getStreamer().EmitWinCFIEndProc(Loc); 368 } 369 CurrentProcedure = ""; 370 CurrentProcedureFramed = false; 371 return false; 372 } 373 374 bool COFFMasmParser::ParseDirectiveAlias(StringRef Directive, SMLoc Loc) { 375 std::string AliasName, ActualName; 376 if (getTok().isNot(AsmToken::Less) || 377 getParser().parseAngleBracketString(AliasName)) 378 return Error(getTok().getLoc(), "expected <aliasName>"); 379 if (getParser().parseToken(AsmToken::Equal)) 380 return addErrorSuffix(" in " + Directive + " directive"); 381 if (getTok().isNot(AsmToken::Less) || 382 getParser().parseAngleBracketString(ActualName)) 383 return Error(getTok().getLoc(), "expected <actualName>"); 384 385 MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName); 386 MCSymbol *Actual = getContext().getOrCreateSymbol(ActualName); 387 388 getStreamer().emitWeakReference(Alias, Actual); 389 390 return false; 391 } 392 393 bool COFFMasmParser::ParseSEHDirectiveAllocStack(StringRef Directive, 394 SMLoc Loc) { 395 int64_t Size; 396 SMLoc SizeLoc = getTok().getLoc(); 397 if (getParser().parseAbsoluteExpression(Size)) 398 return Error(SizeLoc, "expected integer size"); 399 if (Size % 8 != 0) 400 return Error(SizeLoc, "stack size must be a multiple of 8"); 401 getStreamer().EmitWinCFIAllocStack(static_cast<unsigned>(Size), Loc); 402 return false; 403 } 404 405 bool COFFMasmParser::ParseSEHDirectiveEndProlog(StringRef Directive, 406 SMLoc Loc) { 407 getStreamer().EmitWinCFIEndProlog(Loc); 408 return false; 409 } 410 411 namespace llvm { 412 413 MCAsmParserExtension *createCOFFMasmParser() { return new COFFMasmParser; } 414 415 } // end namespace llvm 416