diff --git a/llvm/include/llvm/MC/MCWinCOFFStreamer.h b/llvm/include/llvm/MC/MCWinCOFFStreamer.h --- a/llvm/include/llvm/MC/MCWinCOFFStreamer.h +++ b/llvm/include/llvm/MC/MCWinCOFFStreamer.h @@ -58,6 +58,7 @@ unsigned ByteAlignment) override; void emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; + void emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override; void emitZerofill(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment, SMLoc Loc = SMLoc()) override; void emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, diff --git a/llvm/lib/MC/MCParser/COFFMasmParser.cpp b/llvm/lib/MC/MCParser/COFFMasmParser.cpp --- a/llvm/lib/MC/MCParser/COFFMasmParser.cpp +++ b/llvm/lib/MC/MCParser/COFFMasmParser.cpp @@ -21,6 +21,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbolCOFF.h" #include "llvm/MC/SectionKind.h" #include "llvm/Support/SMLoc.h" #include @@ -53,6 +54,8 @@ bool ParseDirectiveSegmentEnd(StringRef, SMLoc); bool ParseDirectiveIncludelib(StringRef, SMLoc); + bool ParseDirectiveAlias(StringRef, SMLoc); + bool ParseSEHDirectiveAllocStack(StringRef, SMLoc); bool ParseSEHDirectiveEndProlog(StringRef, SMLoc); @@ -124,7 +127,7 @@ // purge // Miscellaneous directives - // alias + addDirectiveHandler<&COFFMasmParser::ParseDirectiveAlias>("alias"); // assume // .fpo addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>( @@ -343,13 +346,11 @@ nextLoc = getTok().getLoc(); } } - MCSymbol *Sym = getContext().getOrCreateSymbol(Label); + MCSymbolCOFF *Sym = cast(getContext().getOrCreateSymbol(Label)); - // Define symbol as simple function - getStreamer().BeginCOFFSymbolDef(Sym); - getStreamer().EmitCOFFSymbolStorageClass(2); - getStreamer().EmitCOFFSymbolType(0x20); - getStreamer().EndCOFFSymbolDef(); + // Define symbol as simple external function + Sym->setExternal(true); + Sym->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT); bool Framed = false; if (getLexer().is(AsmToken::Identifier) && @@ -384,6 +385,25 @@ return false; } +bool COFFMasmParser::ParseDirectiveAlias(StringRef Directive, SMLoc Loc) { + std::string AliasName, ActualName; + if (getTok().isNot(AsmToken::Less) || + getParser().parseAngleBracketString(AliasName)) + return Error(getTok().getLoc(), "expected "); + if (getParser().parseToken(AsmToken::Equal)) + return addErrorSuffix(" in " + Directive + " directive"); + if (getTok().isNot(AsmToken::Less) || + getParser().parseAngleBracketString(ActualName)) + return Error(getTok().getLoc(), "expected "); + + MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName); + MCSymbol *Actual = getContext().getOrCreateSymbol(ActualName); + + getStreamer().emitWeakReference(Alias, Actual); + + return false; +} + bool COFFMasmParser::ParseSEHDirectiveAllocStack(StringRef Directive, SMLoc Loc) { int64_t Size; diff --git a/llvm/lib/MC/MCWinCOFFStreamer.cpp b/llvm/lib/MC/MCWinCOFFStreamer.cpp --- a/llvm/lib/MC/MCWinCOFFStreamer.cpp +++ b/llvm/lib/MC/MCWinCOFFStreamer.cpp @@ -308,6 +308,16 @@ PopSection(); } +void MCWinCOFFStreamer::emitWeakReference(MCSymbol *AliasS, + const MCSymbol *Symbol) { + auto *Alias = cast(AliasS); + emitSymbolAttribute(Alias, MCSA_Weak); + + getAssembler().registerSymbol(*Symbol); + Alias->setVariableValue(MCSymbolRefExpr::create( + Symbol, MCSymbolRefExpr::VK_WEAKREF, getContext())); +} + void MCWinCOFFStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment, SMLoc Loc) { diff --git a/llvm/test/tools/llvm-ml/alias.test b/llvm/test/tools/llvm-ml/alias.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ml/alias.test @@ -0,0 +1,92 @@ +; RUN: llvm-ml -filetype=obj %s | llvm-readobj --syms - | FileCheck %s + +.code + +proc1 PROC + ret +proc1 ENDP + +proc2 PROC + ret +proc2 ENDP + +alias = +; CHECK: Symbol { +; CHECK: Name: t1 +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: Section: IMAGE_SYM_UNDEFINED (0) +; CHECK-NEXT: BaseType: Null +; CHECK-NEXT: ComplexType: Null +; CHECK-NEXT: StorageClass: WeakExternal +; CHECK-NEXT: AuxSymbolCount: 1 +; CHECK-NEXT: AuxWeakExternal { +; CHECK-NEXT: Linked: proc1 +; CHECK-NEXT: Search: Alias +; CHECK-NEXT: } +; CHECK-NEXT: } + +alias = +; CHECK: Symbol { +; CHECK: Name: t2 +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: Section: IMAGE_SYM_UNDEFINED (0) +; CHECK-NEXT: BaseType: Null +; CHECK-NEXT: ComplexType: Null +; CHECK-NEXT: StorageClass: WeakExternal +; CHECK-NEXT: AuxSymbolCount: 1 +; CHECK-NEXT: AuxWeakExternal { +; CHECK-NEXT: Linked: proc2 +; CHECK-NEXT: Search: Alias +; CHECK-NEXT: } +; CHECK-NEXT: } + +alias = +; CHECK: Symbol { +; CHECK: Name: t3 +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: Section: IMAGE_SYM_UNDEFINED (0) +; CHECK-NEXT: BaseType: Null +; CHECK-NEXT: ComplexType: Null +; CHECK-NEXT: StorageClass: WeakExternal +; CHECK-NEXT: AuxSymbolCount: 1 +; CHECK-NEXT: AuxWeakExternal { +; CHECK-NEXT: Linked: foo +; CHECK-NEXT: Search: Alias +; CHECK-NEXT: } +; CHECK-NEXT: } + +alias = +bar PROC + ret +bar ENDP + +; CHECK: Symbol { +; CHECK: Name: t4 +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: Section: IMAGE_SYM_UNDEFINED (0) +; CHECK-NEXT: BaseType: Null +; CHECK-NEXT: ComplexType: Null +; CHECK-NEXT: StorageClass: WeakExternal +; CHECK-NEXT: AuxSymbolCount: 1 +; CHECK-NEXT: AuxWeakExternal { +; CHECK-NEXT: Linked: bar +; CHECK-NEXT: Search: Alias +; CHECK-NEXT: } +; CHECK-NEXT: } + +alias = +; CHECK: Symbol { +; CHECK: Name: t5 +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: Section: IMAGE_SYM_UNDEFINED (0) +; CHECK-NEXT: BaseType: Null +; CHECK-NEXT: ComplexType: Null +; CHECK-NEXT: StorageClass: WeakExternal +; CHECK-NEXT: AuxSymbolCount: 1 +; CHECK-NEXT: AuxWeakExternal { +; CHECK-NEXT: Linked: t2 +; CHECK-NEXT: Search: Alias +; CHECK-NEXT: } +; CHECK-NEXT: } + +END diff --git a/llvm/test/tools/llvm-ml/alias_errors.test b/llvm/test/tools/llvm-ml/alias_errors.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ml/alias_errors.test @@ -0,0 +1,36 @@ +; RUN: not llvm-ml -filetype=asm %s 2>&1 | FileCheck %s + +.code + +foo PROC + ret +foo ENDP + +bar PROC + ret +bar ENDP + +t1: +alias foo = bar +alias foo = +alias = bar + +; CHECK: error: expected +; CHECK: error: expected +; CHECK: error: expected + +t2: +alias +alias , + +; CHECK: error: unexpected token in alias directive +; CHECK: error: unexpected token in alias directive + +t3: +alias +alias + +END \ No newline at end of file