diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp --- a/llvm/lib/MC/MCParser/MasmParser.cpp +++ b/llvm/lib/MC/MCParser/MasmParser.cpp @@ -976,6 +976,8 @@ bool parseDirectiveEnds(StringRef Name, SMLoc NameLoc); bool parseDirectiveNestedEnds(); + bool parseDirectiveExtern(); + /// Parse a directive like ".globl" which accepts a single symbol (which /// should be a label or an external). bool parseDirectiveSymbolAttribute(MCSymbolAttr Attr); @@ -2405,8 +2407,7 @@ case DK_ORG: return parseDirectiveOrg(); case DK_EXTERN: - eatToEndOfStatement(); // .extern is the default, ignore it. - return false; + return parseDirectiveExtern(); case DK_PUBLIC: return parseDirectiveSymbolAttribute(MCSA_Global); case DK_COMM: @@ -6019,6 +6020,37 @@ return false; } +bool MasmParser::parseDirectiveExtern() { + // .extern is the default - but we still need to take any provided type info. + auto parseOp = [&]() -> bool { + StringRef Name; + SMLoc NameLoc = getTok().getLoc(); + if (parseIdentifier(Name)) + return Error(NameLoc, "expected name"); + if (parseToken(AsmToken::Colon)) + return true; + + StringRef TypeName; + SMLoc TypeLoc = getTok().getLoc(); + if (parseIdentifier(TypeName)) + return Error(TypeLoc, "expected type"); + AsmTypeInfo Type; + if (lookUpType(TypeName, Type)) + return Error(TypeLoc, "unrecognized type"); + KnownType[Name.lower()] = Type; + + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + Sym->setExternal(true); + getStreamer().emitSymbolAttribute(Sym, MCSA_Extern); + + return false; + }; + + if (parseMany(parseOp)) + return addErrorSuffix(" in directive 'extern'"); + return false; +} + /// parseDirectiveSymbolAttribute /// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ] bool MasmParser::parseDirectiveSymbolAttribute(MCSymbolAttr Attr) { diff --git a/llvm/test/tools/llvm-ml/extern.asm b/llvm/test/tools/llvm-ml/extern.asm new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ml/extern.asm @@ -0,0 +1,9 @@ +; RUN: llvm-ml -m32 -filetype=s %s /Fo - | FileCheck %s +; RUN: llvm-ml -m64 -filetype=s %s /Fo - | FileCheck %s + +extern foo : dword, bar : word + +END + +; CHECK: .extern foo +; CHECK: .extern bar diff --git a/llvm/test/tools/llvm-ml/indirect_branch.asm b/llvm/test/tools/llvm-ml/indirect_branch.asm --- a/llvm/test/tools/llvm-ml/indirect_branch.asm +++ b/llvm/test/tools/llvm-ml/indirect_branch.asm @@ -1,6 +1,13 @@ ; RUN: llvm-ml -m64 -filetype=s %s /Fo - | FileCheck %s --check-prefixes=CHECK-64,CHECK ; RUN: llvm-ml -m32 -filetype=s %s /Fo - | FileCheck %s --check-prefixes=CHECK-32,CHECK +ifdef rax + extern fn_ref_extern : qword +else + extern fn_ref_extern : dword +endif +extern fn_ref_extern_word : word + .data ifdef rax @@ -186,3 +193,58 @@ je [t16]; ; CHECK-LABEL: t16: ; CHECK: je t16 + +t17: +call fn_ref_extern +jmp fn_ref_extern +; CHECK-LABEL: t17: +; CHECK-64: call qword ptr [rip + fn_ref_extern] +; CHECK-64: jmp qword ptr [rip + fn_ref_extern] +; CHECK-32: call dword ptr [fn_ref_extern] +; CHECK-32: jmp dword ptr [fn_ref_extern] + +t18: +call [fn_ref_extern] +jmp [fn_ref_extern] +; CHECK-LABEL: t18: +; CHECK-64: call qword ptr [rip + fn_ref_extern] +; CHECK-64: jmp qword ptr [rip + fn_ref_extern] +; CHECK-32: call dword ptr [fn_ref_extern] +; CHECK-32: jmp dword ptr [fn_ref_extern] + +ifdef rax + t19: + call qword ptr [fn_ref_extern] + jmp qword ptr [fn_ref_extern] + ; CHECK-64-LABEL: t19: + ; CHECK-64: call qword ptr [rip + fn_ref_extern] + ; CHECK-64: jmp qword ptr [rip + fn_ref_extern] +else + t19: + call dword ptr [fn_ref_extern] + jmp dword ptr [fn_ref_extern] + ; CHECK-32-LABEL: t19: + ; CHECK-32: call dword ptr [fn_ref_extern] + ; CHECK-32: jmp dword ptr [fn_ref_extern] + + t20: + call fn_ref_extern_word + jmp fn_ref_extern_word + ; CHECK-32-LABEL: t20: + ; CHECK-32: call word ptr [fn_ref_extern_word] + ; CHECK-32-NEXT: jmp word ptr [fn_ref_extern_word] + + t21: + call [fn_ref_extern_word] + jmp [fn_ref_extern_word] + ; CHECK-32-LABEL: t21: + ; CHECK-32: call word ptr [fn_ref_extern_word] + ; CHECK-32-NEXT: jmp word ptr [fn_ref_extern_word] + + t22: + call word ptr [fn_ref_extern_word] + jmp word ptr [fn_ref_extern_word] + ; CHECK-32-LABEL: t22: + ; CHECK-32: call word ptr [fn_ref_extern_word] + ; CHECK-32-NEXT: jmp word ptr [fn_ref_extern_word] +endif