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
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 {
/// 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;
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)
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;
SF_ClassMask = 0x00FF,
SF_ClassShift = 0,
- SF_WeakExternal = 0x0100,
- SF_SafeSEH = 0x0200,
+ SF_SafeSEH = 0x0100,
+ SF_WeakExternalCharacteristicsMask = 0x0E00,
+ SF_WeakExternalCharacteristicsShift = 9,
};
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 {
case MCSA_Memtag:
OS << "\t.memtag\t";
break;
+ case MCSA_WeakAntiDep:
+ OS << "\t.weak_anti_dep\t";
+ break;
}
Symbol->print(OS, MAI);
case MCSA_Invalid:
case MCSA_IndirectSymbol:
case MCSA_Exported:
+ case MCSA_WeakAntiDep:
return false;
case MCSA_NoDeadStrip:
}
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) {
case SymbolRef: {
const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(this);
const MCSymbol &Sym = SRE->getSymbol();
+ if (Sym.isWeakExternal())
+ return nullptr;
return Sym.getFragment();
}
case MCSA_LGlobal:
case MCSA_Exported:
case MCSA_Memtag:
+ case MCSA_WeakAntiDep:
return false;
case MCSA_Global:
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;
}
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.
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)) {
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:
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;
// 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 {
--- /dev/null
+// 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: }