From 10c17c97ebaf81ac26f6830e51a7a57ddcf63cd2 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Mon, 17 Apr 2023 13:15:46 -0700 Subject: [PATCH] [COFF] Add MC support for emitting IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY symbols This is mostly useful for ARM64EC, which uses such symbols extensively. One interesting quirk of ARM64EC is that we need to be able to emit weak symbols that point at each other (so if either symbol is defined elsewhere, both symbols point at the definition). This required a few changes to the way we handle weak symbols on Windows. Differential Revision: https://reviews.llvm.org/D145208 --- llvm/include/llvm/MC/MCDirectives.h | 1 + llvm/include/llvm/MC/MCSymbol.h | 13 +++++-- llvm/include/llvm/MC/MCSymbolCOFF.h | 16 +++++--- llvm/lib/MC/MCAsmStreamer.cpp | 3 ++ llvm/lib/MC/MCELFStreamer.cpp | 1 + llvm/lib/MC/MCExpr.cpp | 3 ++ llvm/lib/MC/MCMachOStreamer.cpp | 1 + llvm/lib/MC/MCParser/AsmParser.cpp | 2 +- llvm/lib/MC/MCParser/COFFAsmParser.cpp | 2 + llvm/lib/MC/MCWinCOFFStreamer.cpp | 6 ++- llvm/lib/MC/WinCOFFObjectWriter.cpp | 4 +- llvm/test/MC/COFF/addrsig.s | 11 +++++- llvm/test/MC/COFF/alias.s | 2 +- llvm/test/MC/COFF/weak-anti-dep.s | 68 ++++++++++++++++++++++++++++++++++ 14 files changed, 118 insertions(+), 15 deletions(-) create mode 100644 llvm/test/MC/COFF/weak-anti-dep.s diff --git a/llvm/include/llvm/MC/MCDirectives.h b/llvm/include/llvm/MC/MCDirectives.h index b9668a0..fcab56f 100644 --- a/llvm/include/llvm/MC/MCDirectives.h +++ b/llvm/include/llvm/MC/MCDirectives.h @@ -46,6 +46,7 @@ enum MCSymbolAttr { MCSA_WeakDefinition, ///< .weak_definition (MachO) MCSA_WeakReference, ///< .weak_reference (MachO) MCSA_WeakDefAutoPrivate, ///< .weak_def_can_be_hidden (MachO) + MCSA_WeakAntiDep, ///< .weak_anti_dep (COFF) MCSA_Memtag, ///< .memtag (ELF) }; diff --git a/llvm/include/llvm/MC/MCSymbol.h b/llvm/include/llvm/MC/MCSymbol.h index 8954960..f59821d 100644 --- a/llvm/include/llvm/MC/MCSymbol.h +++ b/llvm/include/llvm/MC/MCSymbol.h @@ -102,6 +102,9 @@ protected: /// This symbol is private extern. mutable unsigned IsPrivateExtern : 1; + /// This symbol is weak external. + mutable unsigned IsWeakExternal : 1; + /// LLVM RTTI discriminator. This is actually a SymbolKind enumerator, but is /// unsigned to avoid sign extension and achieve better bitpacking with MSVC. unsigned Kind : 3; @@ -161,8 +164,8 @@ protected: MCSymbol(SymbolKind Kind, const StringMapEntry *Name, bool isTemporary) : IsTemporary(isTemporary), IsRedefinable(false), IsUsed(false), IsRegistered(false), IsExternal(false), IsPrivateExtern(false), - Kind(Kind), IsUsedInReloc(false), SymbolContents(SymContentsUnset), - CommonAlignLog2(0), Flags(0) { + IsWeakExternal(false), Kind(Kind), IsUsedInReloc(false), + SymbolContents(SymContentsUnset), CommonAlignLog2(0), Flags(0) { Offset = 0; FragmentAndHasName.setInt(!!Name); if (Name) @@ -394,8 +397,10 @@ public: MCFragment *getFragment(bool SetUsed = true) const { MCFragment *Fragment = FragmentAndHasName.getPointer(); - if (Fragment || !isVariable()) + if (Fragment || !isVariable() || isWeakExternal()) return Fragment; + // If the symbol is a non-weak alias, get information about + // the aliasee. (Don't try to resolve weak aliases.) Fragment = getVariableValue(SetUsed)->findAssociatedFragment(); FragmentAndHasName.setPointer(Fragment); return Fragment; @@ -407,6 +412,8 @@ public: bool isPrivateExtern() const { return IsPrivateExtern; } void setPrivateExtern(bool Value) { IsPrivateExtern = Value; } + bool isWeakExternal() const { return IsWeakExternal; } + /// print - Print the value to the stream \p OS. void print(raw_ostream &OS, const MCAsmInfo *MAI) const; diff --git a/llvm/include/llvm/MC/MCSymbolCOFF.h b/llvm/include/llvm/MC/MCSymbolCOFF.h index b25993c..7f077c7 100644 --- a/llvm/include/llvm/MC/MCSymbolCOFF.h +++ b/llvm/include/llvm/MC/MCSymbolCOFF.h @@ -23,8 +23,9 @@ class MCSymbolCOFF : public MCSymbol { SF_ClassMask = 0x00FF, SF_ClassShift = 0, - SF_WeakExternal = 0x0100, - SF_SafeSEH = 0x0200, + SF_SafeSEH = 0x0100, + SF_WeakExternalCharacteristicsMask = 0x0E00, + SF_WeakExternalCharacteristicsShift = 9, }; public: @@ -45,11 +46,14 @@ public: modifyFlags(StorageClass << SF_ClassShift, SF_ClassMask); } - bool isWeakExternal() const { - return getFlags() & SF_WeakExternal; + COFF::WeakExternalCharacteristics getWeakExternalCharacteristics() const { + return static_cast((getFlags() & SF_WeakExternalCharacteristicsMask) >> + SF_WeakExternalCharacteristicsShift); } - void setIsWeakExternal() const { - modifyFlags(SF_WeakExternal, SF_WeakExternal); + void setIsWeakExternal(COFF::WeakExternalCharacteristics Characteristics) const { + IsWeakExternal = true; + modifyFlags(Characteristics << SF_WeakExternalCharacteristicsShift, + SF_WeakExternalCharacteristicsMask); } bool isSafeSEH() const { diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index c11d28b..6f21566 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -772,6 +772,9 @@ bool MCAsmStreamer::emitSymbolAttribute(MCSymbol *Symbol, case MCSA_Memtag: OS << "\t.memtag\t"; break; + case MCSA_WeakAntiDep: + OS << "\t.weak_anti_dep\t"; + break; } Symbol->print(OS, MAI); diff --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp index 8dd002f..303eb16 100644 --- a/llvm/lib/MC/MCELFStreamer.cpp +++ b/llvm/lib/MC/MCELFStreamer.cpp @@ -216,6 +216,7 @@ bool MCELFStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { case MCSA_Invalid: case MCSA_IndirectSymbol: case MCSA_Exported: + case MCSA_WeakAntiDep: return false; case MCSA_NoDeadStrip: diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp index 04682fd..68cd88f 100644 --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -761,6 +761,9 @@ bool MCExpr::evaluateAsValue(MCValue &Res, const MCAsmLayout &Layout) const { } static bool canExpand(const MCSymbol &Sym, bool InSet) { + if (Sym.isWeakExternal()) + return false; + const MCExpr *Expr = Sym.getVariableValue(); const auto *Inner = dyn_cast(Expr); if (Inner) { diff --git a/llvm/lib/MC/MCMachOStreamer.cpp b/llvm/lib/MC/MCMachOStreamer.cpp index 986c0c2c..6711ff9 100644 --- a/llvm/lib/MC/MCMachOStreamer.cpp +++ b/llvm/lib/MC/MCMachOStreamer.cpp @@ -358,6 +358,7 @@ bool MCMachOStreamer::emitSymbolAttribute(MCSymbol *Sym, case MCSA_LGlobal: case MCSA_Exported: case MCSA_Memtag: + case MCSA_WeakAntiDep: return false; case MCSA_Global: diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index c49e513..254c747 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -6371,7 +6371,7 @@ static bool isSymbolUsedInExpression(const MCSymbol *Sym, const MCExpr *Value) { case MCExpr::SymbolRef: { const MCSymbol &S = static_cast(Value)->getSymbol(); - if (S.isVariable()) + if (S.isVariable() && !S.isWeakExternal()) return isSymbolUsedInExpression(Sym, S.getVariableValue()); return &S == Sym; } diff --git a/llvm/lib/MC/MCParser/COFFAsmParser.cpp b/llvm/lib/MC/MCParser/COFFAsmParser.cpp index fc3d1e9..3f88257 100644 --- a/llvm/lib/MC/MCParser/COFFAsmParser.cpp +++ b/llvm/lib/MC/MCParser/COFFAsmParser.cpp @@ -67,6 +67,7 @@ class COFFAsmParser : public MCAsmParserExtension { addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak_anti_dep"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveCGProfile>(".cg_profile"); // Win64 EH directives. @@ -281,6 +282,7 @@ bool COFFAsmParser::ParseSectionFlags(StringRef SectionName, bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { MCSymbolAttr Attr = StringSwitch(Directive) .Case(".weak", MCSA_Weak) + .Case(".weak_anti_dep", MCSA_WeakAntiDep) .Default(MCSA_Invalid); assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); if (getLexer().isNot(AsmToken::EndOfStatement)) { diff --git a/llvm/lib/MC/MCWinCOFFStreamer.cpp b/llvm/lib/MC/MCWinCOFFStreamer.cpp index c9a9681..ad0b1c1 100644 --- a/llvm/lib/MC/MCWinCOFFStreamer.cpp +++ b/llvm/lib/MC/MCWinCOFFStreamer.cpp @@ -115,7 +115,11 @@ bool MCWinCOFFStreamer::emitSymbolAttribute(MCSymbol *S, default: return false; case MCSA_WeakReference: case MCSA_Weak: - Symbol->setIsWeakExternal(); + Symbol->setIsWeakExternal(COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS); + Symbol->setExternal(true); + break; + case MCSA_WeakAntiDep: + Symbol->setIsWeakExternal(COFF::IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY); Symbol->setExternal(true); break; case MCSA_Global: diff --git a/llvm/lib/MC/WinCOFFObjectWriter.cpp b/llvm/lib/MC/WinCOFFObjectWriter.cpp index 4927ea6..6687fd6 100644 --- a/llvm/lib/MC/WinCOFFObjectWriter.cpp +++ b/llvm/lib/MC/WinCOFFObjectWriter.cpp @@ -414,9 +414,9 @@ void WinCOFFObjectWriter::DefineSymbol(const MCSymbol &MCSym, Sym->Aux.resize(1); memset(&Sym->Aux[0], 0, sizeof(Sym->Aux[0])); Sym->Aux[0].AuxType = ATWeakExternal; - Sym->Aux[0].Aux.WeakExternal.TagIndex = 0; + Sym->Aux[0].Aux.WeakExternal.TagIndex = 0; // Filled in later Sym->Aux[0].Aux.WeakExternal.Characteristics = - COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS; + cast(MCSym).getWeakExternalCharacteristics(); } else { if (!Base) Sym->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE; diff --git a/llvm/test/MC/COFF/addrsig.s b/llvm/test/MC/COFF/addrsig.s index 7c3b25d..a181bb0 100644 --- a/llvm/test/MC/COFF/addrsig.s +++ b/llvm/test/MC/COFF/addrsig.s @@ -3,7 +3,7 @@ // CHECK: Name: .llvm_addrsig // CHECK-NEXT: VirtualSize: 0x0 // CHECK-NEXT: VirtualAddress: 0x0 -// CHECK-NEXT: RawDataSize: 4 +// CHECK-NEXT: RawDataSize: 6 // CHECK-NEXT: PointerToRawData: // CHECK-NEXT: PointerToRelocations: 0x0 // CHECK-NEXT: PointerToLineNumbers: 0x0 @@ -46,6 +46,8 @@ // CHECK-NEXT: Sym: g3 (11) // CHECK-NEXT: Sym: local (10) // CHECK-NEXT: Sym: .data (2) +// CHECK-NEXT: Sym: weak_sym (12) +// CHECK-NEXT: Sym: .data (2) // CHECK-NEXT: ] .globl g1 @@ -64,3 +66,10 @@ local: .data .Llocal: + +.weak weak_sym +weak_sym: +.addrsig_sym weak_sym + +.set .Lalias_weak_sym, weak_sym +.addrsig_sym .Lalias_weak_sym diff --git a/llvm/test/MC/COFF/alias.s b/llvm/test/MC/COFF/alias.s index b6828c6..cfb44ca 100644 --- a/llvm/test/MC/COFF/alias.s +++ b/llvm/test/MC/COFF/alias.s @@ -24,7 +24,7 @@ weak_aliased_to_external = external2 // CHECK: 0x0 IMAGE_REL_I386_DIR32 external_aliased_to_local // CHECK: 0x4 IMAGE_REL_I386_DIR32 external1 // CHECK: 0x8 IMAGE_REL_I386_DIR32 global_aliased_to_local -// CHECK: 0xC IMAGE_REL_I386_DIR32 external2 +// CHECK: 0xC IMAGE_REL_I386_DIR32 weak_aliased_to_external // CHECK: ] // CHECK: Symbols [ // CHECK-NEXT: Symbol { diff --git a/llvm/test/MC/COFF/weak-anti-dep.s b/llvm/test/MC/COFF/weak-anti-dep.s new file mode 100644 index 0000000..dbf5ffc --- /dev/null +++ b/llvm/test/MC/COFF/weak-anti-dep.s @@ -0,0 +1,68 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-win32 %s | llvm-readobj --symbols - | FileCheck %s + +// CHECK: Symbol { +// CHECK-NEXT: Name: .text +// CHECK: Symbol { +// CHECK-NEXT: Name: .data +// CHECK: Symbol { +// CHECK-NEXT: Name: .bss + +.weak_anti_dep a +a = b + +// CHECK: Symbol { +// CHECK-NEXT: Name: a +// CHECK-NEXT: Value: 0 +// CHECK-NEXT: Section: IMAGE_SYM_UNDEFINED (0) +// CHECK-NEXT: BaseType: Null (0x0) +// CHECK-NEXT: ComplexType: Null (0x0) +// CHECK-NEXT: StorageClass: WeakExternal (0x69) +// CHECK-NEXT: AuxSymbolCount: 1 +// CHECK-NEXT: AuxWeakExternal { +// CHECK-NEXT: Linked: b (8) +// CHECK-NEXT: Search: AntiDependency (0x4) +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: b +// CHECK-NEXT: Value: 0 +// CHECK-NEXT: Section: IMAGE_SYM_UNDEFINED (0) +// CHECK-NEXT: BaseType: Null (0x0) +// CHECK-NEXT: ComplexType: Null (0x0) +// CHECK-NEXT: StorageClass: External (0x2) +// CHECK-NEXT: AuxSymbolCount: 0 +// CHECK-NEXT: } + + +.weak_anti_dep r1 +.weak_anti_dep r2 +r1 = r2 +r2 = r1 + + +// CHECK: Symbol { +// CHECK-NEXT: Name: r1 +// CHECK-NEXT: Value: 0 +// CHECK-NEXT: Section: IMAGE_SYM_UNDEFINED (0) +// CHECK-NEXT: BaseType: Null (0x0) +// CHECK-NEXT: ComplexType: Null (0x0) +// CHECK-NEXT: StorageClass: WeakExternal (0x69) +// CHECK-NEXT: AuxSymbolCount: 1 +// CHECK-NEXT: AuxWeakExternal { +// CHECK-NEXT: Linked: r2 (11) +// CHECK-NEXT: Search: AntiDependency (0x4) +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: r2 +// CHECK-NEXT: Value: 0 +// CHECK-NEXT: Section: IMAGE_SYM_UNDEFINED (0) +// CHECK-NEXT: BaseType: Null (0x0) +// CHECK-NEXT: ComplexType: Null (0x0) +// CHECK-NEXT: StorageClass: WeakExternal (0x69) +// CHECK-NEXT: AuxSymbolCount: 1 +// CHECK-NEXT: AuxWeakExternal { +// CHECK-NEXT: Linked: r1 (9) +// CHECK-NEXT: Search: AntiDependency (0x4) +// CHECK-NEXT: } +// CHECK-NEXT: } -- 2.7.4