[COFF] Add MC support for emitting IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY symbols
authorEli Friedman <efriedma@quicinc.com>
Fri, 3 Mar 2023 02:09:14 +0000 (18:09 -0800)
committerEli Friedman <efriedma@quicinc.com>
Fri, 7 Apr 2023 21:05:45 +0000 (14:05 -0700)
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

13 files changed:
llvm/include/llvm/MC/MCDirectives.h
llvm/include/llvm/MC/MCSymbol.h
llvm/include/llvm/MC/MCSymbolCOFF.h
llvm/lib/MC/MCAsmStreamer.cpp
llvm/lib/MC/MCELFStreamer.cpp
llvm/lib/MC/MCExpr.cpp
llvm/lib/MC/MCMachOStreamer.cpp
llvm/lib/MC/MCParser/AsmParser.cpp
llvm/lib/MC/MCParser/COFFAsmParser.cpp
llvm/lib/MC/MCWinCOFFStreamer.cpp
llvm/lib/MC/WinCOFFObjectWriter.cpp
llvm/test/MC/COFF/alias.s
llvm/test/MC/COFF/weak-anti-dep.s [new file with mode: 0644]

index b9668a0..19d54b5 100644 (file)
@@ -47,6 +47,7 @@ enum MCSymbolAttr {
   MCSA_WeakReference,           ///< .weak_reference (MachO)
   MCSA_WeakDefAutoPrivate,      ///< .weak_def_can_be_hidden (MachO)
   MCSA_Memtag,                  ///< .memtag (ELF)
+  MCSA_WeakAntiDep,             ///< .weak_anti_dep (COFF)
 };
 
 enum MCAssemblerFlag {
index 8954960..22f2a1d 100644 (file)
@@ -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<bool> *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)
@@ -407,6 +410,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;
 
index 94087ce..32f55cd 100644 (file)
@@ -22,8 +22,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:
@@ -44,11 +45,14 @@ public:
     modifyFlags(StorageClass << SF_ClassShift, SF_ClassMask);
   }
 
-  bool isWeakExternal() const {
-    return getFlags() & SF_WeakExternal;
+  COFF::WeakExternalCharacteristics getWeakExternalCharacteristics() const {
+    return static_cast<COFF::WeakExternalCharacteristics>((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 {
index c11d28b..6f21566 100644 (file)
@@ -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);
index 8dd002f..303eb16 100644 (file)
@@ -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:
index 04682fd..5c061b5 100644 (file)
@@ -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<MCSymbolRefExpr>(Expr);
   if (Inner) {
@@ -997,6 +1000,8 @@ MCFragment *MCExpr::findAssociatedFragment() const {
   case SymbolRef: {
     const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(this);
     const MCSymbol &Sym = SRE->getSymbol();
+    if (Sym.isWeakExternal())
+      return nullptr;
     return Sym.getFragment();
   }
 
index 986c0c2..6711ff9 100644 (file)
@@ -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:
index c49e513..254c747 100644 (file)
@@ -6371,7 +6371,7 @@ static bool isSymbolUsedInExpression(const MCSymbol *Sym, const MCExpr *Value) {
   case MCExpr::SymbolRef: {
     const MCSymbol &S =
         static_cast<const MCSymbolRefExpr *>(Value)->getSymbol();
-    if (S.isVariable())
+    if (S.isVariable() && !S.isWeakExternal())
       return isSymbolUsedInExpression(Sym, S.getVariableValue());
     return &S == Sym;
   }
index fc3d1e9..3f88257 100644 (file)
@@ -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<MCSymbolAttr>(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)) {
index c9a9681..ad0b1c1 100644 (file)
@@ -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:
index 4927ea6..6687fd6 100644 (file)
@@ -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<MCSymbolCOFF>(MCSym).getWeakExternalCharacteristics();
   } else {
     if (!Base)
       Sym->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE;
index b6828c6..cfb44ca 100644 (file)
@@ -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 (file)
index 0000000..dbf5ffc
--- /dev/null
@@ -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:  }