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 required a few
changes to the way we handle weak symbols on Windows.

Differential Revision: https://reviews.llvm.org/D145208
  • Loading branch information
efriedma-quic committed Apr 7, 2023
1 parent 4b46509 commit fffdb7e
Show file tree
Hide file tree
Showing 13 changed files with 107 additions and 13 deletions.
1 change: 1 addition & 0 deletions llvm/include/llvm/MC/MCDirectives.h
Expand Up @@ -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 {
Expand Down
9 changes: 7 additions & 2 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;
FragmentAndHasName.setInt(!!Name);
if (Name)
Expand Down Expand Up @@ -407,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
16 changes: 10 additions & 6 deletions llvm/include/llvm/MC/MCSymbolCOFF.h
Expand Up @@ -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:
Expand All @@ -44,11 +45,14 @@ 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 setIsWeakExternal(COFF::WeakExternalCharacteristics Characteristics) const {
IsWeakExternal = true;
modifyFlags(Characteristics << SF_WeakExternalCharacteristicsShift,
SF_WeakExternalCharacteristicsMask);
}

bool isSafeSEH() const {
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/MC/MCAsmStreamer.cpp
Expand Up @@ -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);
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
5 changes: 5 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 Expand Up @@ -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();
}

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
6 changes: 5 additions & 1 deletion llvm/lib/MC/MCWinCOFFStreamer.cpp
Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/MC/WinCOFFObjectWriter.cpp
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/MC/COFF/alias.s
Expand Up @@ -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 {
Expand Down
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 fffdb7e

Please sign in to comment.