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 @@ -53,6 +53,8 @@ bool ParseDirectiveSegmentEnd(StringRef, SMLoc); bool ParseDirectiveIncludelib(StringRef, SMLoc); + bool ParseDirectiveAlias(StringRef, SMLoc); + bool ParseSEHDirectiveAllocStack(StringRef, SMLoc); bool ParseSEHDirectiveEndProlog(StringRef, SMLoc); @@ -124,7 +126,7 @@ // purge // Miscellaneous directives - // alias + addDirectiveHandler<&COFFMasmParser::ParseDirectiveAlias>("alias"); // assume // .fpo addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>( @@ -384,6 +386,26 @@ 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); + + Alias->setVariableValue(MCSymbolRefExpr::create(Actual, getContext())); + 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,18 @@ PopSection(); } +void MCWinCOFFStreamer::emitWeakReference(MCSymbol *AliasS, + const MCSymbol *Symbol) { + auto *Alias = cast(AliasS); + Alias->setIsWeakExternal(); + + BeginCOFFSymbolDef(AliasS); + EmitCOFFSymbolStorageClass( + COFF::SymbolStorageClass::IMAGE_SYM_CLASS_WEAK_EXTERNAL); + EmitCOFFSymbolType(COFF::SymbolBaseType::IMAGE_SYM_TYPE_NULL); + EndCOFFSymbolDef(); +} + 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