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_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)
};
/// 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)
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;
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 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: 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
// 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
.data
.Llocal:
+
+.weak weak_sym
+weak_sym:
+.addrsig_sym weak_sym
+
+.set .Lalias_weak_sym, weak_sym
+.addrsig_sym .Lalias_weak_sym
// 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: }