Skip to content

Commit

Permalink
[COFF] Add MC support for emitting IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY …
Browse files Browse the repository at this point in the history
…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 handling is
currently restricted to weak_anti_dep symbols, because we depend on the
current behavior of resolving weak symbols in some cases.

Differential Revision: https://reviews.llvm.org/D145208
  • Loading branch information
efriedma-quic committed Jun 7, 2023
1 parent f3df0cf commit 7198bac
Show file tree
Hide file tree
Showing 13 changed files with 121 additions and 15 deletions.
1 change: 1 addition & 0 deletions llvm/include/llvm/MC/MCDirectives.h
Expand Up @@ -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)
};

Expand Down
13 changes: 10 additions & 3 deletions llvm/include/llvm/MC/MCSymbol.h
Expand Up @@ -102,6 +102,9 @@ class MCSymbol {
/// 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;
Expand Down Expand Up @@ -161,8 +164,8 @@ class MCSymbol {
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;
HasName = !!Name;
if (Name)
Expand Down Expand Up @@ -393,8 +396,10 @@ class MCSymbol {
}

MCFragment *getFragment(bool SetUsed = true) const {
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();
return Fragment;
}
Expand All @@ -405,6 +410,8 @@ class MCSymbol {
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;

Expand Down
18 changes: 12 additions & 6 deletions llvm/include/llvm/MC/MCSymbolCOFF.h
Expand Up @@ -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:
Expand All @@ -45,11 +46,16 @@ class MCSymbolCOFF : public MCSymbol {
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 setWeakExternalCharacteristics(COFF::WeakExternalCharacteristics Characteristics) const {
modifyFlags(Characteristics << SF_WeakExternalCharacteristicsShift,
SF_WeakExternalCharacteristicsMask);
}
void setIsWeakExternal(bool WeakExt) const {
IsWeakExternal = WeakExt;
}

bool isSafeSEH() const {
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/MC/MCAsmStreamer.cpp
Expand Up @@ -773,6 +773,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);
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/MC/MCELFStreamer.cpp
Expand Up @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/MC/MCExpr.cpp
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/MC/MCMachOStreamer.cpp
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/MC/MCParser/AsmParser.cpp
Expand Up @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/MC/MCParser/COFFAsmParser.cpp
Expand Up @@ -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.
Expand Down Expand Up @@ -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)) {
Expand Down
7 changes: 6 additions & 1 deletion llvm/lib/MC/MCWinCOFFStreamer.cpp
Expand Up @@ -115,9 +115,14 @@ bool MCWinCOFFStreamer::emitSymbolAttribute(MCSymbol *S,
default: return false;
case MCSA_WeakReference:
case MCSA_Weak:
Symbol->setIsWeakExternal();
Symbol->setWeakExternalCharacteristics(COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS);
Symbol->setExternal(true);
break;
case MCSA_WeakAntiDep:
Symbol->setWeakExternalCharacteristics(COFF::IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY);
Symbol->setExternal(true);
Symbol->setIsWeakExternal(true);
break;
case MCSA_Global:
Symbol->setExternal(true);
break;
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/MC/WinCOFFObjectWriter.cpp
Expand Up @@ -385,7 +385,7 @@ void WinCOFFObjectWriter::DefineSymbol(const MCSymbol &MCSym,
}

COFFSymbol *Local = nullptr;
if (cast<MCSymbolCOFF>(MCSym).isWeakExternal()) {
if (cast<MCSymbolCOFF>(MCSym).getWeakExternalCharacteristics()) {
Sym->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL;
Sym->Section = nullptr;

Expand All @@ -407,9 +407,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;
Expand Down
11 changes: 10 additions & 1 deletion llvm/test/MC/COFF/addrsig.s
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
68 changes: 68 additions & 0 deletions 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: }

0 comments on commit 7198bac

Please sign in to comment.