MC: Rework .weakref

Use a variable symbol without any specifier instead of VK_WEAKREF.
Add code in ELFObjectWriter::executePostLayoutBinding to check
whether the target should be made an undefined weak symbol.

This change fixes several issues:

* Unreferenced `.weakref alias, target` no longer creates an undefined `target`.
* When `alias` is already defined, report an error instead of crashing.

.weakref is specific to ELF. llvm-ml has reused the VK_WEAKREF name for
a different concept. wasm incorrectly copied the ELF implementation.
Remove it.
This commit is contained in:
Fangrui Song
2025-05-25 21:09:55 -07:00
parent eda3e96b40
commit 95756e67c2
14 changed files with 76 additions and 75 deletions

View File

@@ -110,10 +110,10 @@ foo:
# CHECK-NEXT: R_AMDGPU_ABS64 weak_var0 0x0
# CHECK-NEXT: R_AMDGPU_ABS64 weak_var1 0x0
# CHECK-NEXT: R_AMDGPU_ABS64 weak_var2 0x0
# CHECK-NEXT: R_AMDGPU_ABS64 temp 0x0
# CHECK-NEXT: R_AMDGPU_ABS64 weakref_alias_var0 0x0
# CHECK-NEXT: R_AMDGPU_ABS64 weakref_alias_var1 0x0
# CHECK-NEXT: R_AMDGPU_ABS64 weakref_alias_var2 0x0
# CHECK-NEXT: R_AMDGPU_ABS64 temp 0x0
# CHECK-NEXT: }
# CHECK-NEXT: ]

View File

@@ -149,6 +149,8 @@ public:
DenseMap<const MCSectionELF *, std::vector<ELFRelocationEntry>> Relocations;
DenseMap<const MCSymbolELF *, const MCSymbolELF *> Renames;
// .weakref aliases
SmallVector<const MCSymbolELF *, 0> Weakrefs;
bool IsLittleEndian = false;
bool SeenGnuAbi = false;
std::optional<uint8_t> OverrideABIVersion;

View File

@@ -53,7 +53,7 @@ public:
void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;
void emitLabelAtPos(MCSymbol *Symbol, SMLoc Loc, MCDataFragment &F,
uint64_t Offset) override;
void emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override;
void emitWeakReference(MCSymbol *Alias, const MCSymbol *Target) override;
bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) override;

View File

@@ -119,7 +119,7 @@ public:
SMLoc Loc = SMLoc()) override;
void emitULEB128Value(const MCExpr *Value) override;
void emitSLEB128Value(const MCExpr *Value) override;
void emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override;
void emitWeakReference(MCSymbol *Alias, const MCSymbol *Target) override;
void changeSection(MCSection *Section, uint32_t Subsection = 0) override;
void switchSectionNoPrint(MCSection *Section) override;
void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;

View File

@@ -38,8 +38,8 @@ public:
bool isBindingSet() const;
void setIsWeakrefUsedInReloc() const;
bool isWeakrefUsedInReloc() const;
void setIsWeakref() const;
bool isWeakref() const;
void setIsSignature() const;
bool isSignature() const;

View File

@@ -44,7 +44,6 @@ public:
void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;
void emitLabelAtPos(MCSymbol *Symbol, SMLoc Loc, MCDataFragment &F,
uint64_t Offset) override;
void emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override;
bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) override;

View File

@@ -476,10 +476,9 @@ bool ELFWriter::isInSymtab(const MCSymbolELF &Symbol, bool Used, bool Renamed) {
if (const auto *T = dyn_cast<MCTargetExpr>(Expr))
if (T->inlineAssignedExpr())
return false;
if (const MCSymbolRefExpr *Ref = dyn_cast<MCSymbolRefExpr>(Expr)) {
if (Ref->getKind() == MCSymbolRefExpr::VK_WEAKREF)
return false;
}
// The .weakref alias does not appear in the symtab.
if (Symbol.isWeakref())
return false;
}
if (Used)
@@ -531,10 +530,8 @@ void ELFWriter::computeSymbolTable(const RevGroupMapTy &RevGroupMap) {
for (auto It : llvm::enumerate(Asm.symbols())) {
const auto &Symbol = cast<MCSymbolELF>(It.value());
bool Used = Symbol.isUsedInReloc();
bool WeakrefUsed = Symbol.isWeakrefUsedInReloc();
bool isSignature = Symbol.isSignature();
if (!isInSymtab(Symbol, Used || WeakrefUsed || isSignature,
if (!isInSymtab(Symbol, Used || isSignature,
OWriter.Renames.count(&Symbol)))
continue;
@@ -1245,6 +1242,21 @@ void ELFObjectWriter::executePostLayoutBinding() {
Sym = Sym->getSection().getBeginSymbol();
Sym->setUsedInReloc();
}
// For each `.weakref alias, target`, if the variable `alias` is registered
// (typically through MCObjectStreamer::visitUsedSymbol), register `target`.
// If `target` was unregistered before (not directly referenced or defined),
// make it weak.
for (const MCSymbol *Alias : Weakrefs) {
if (!Alias->isRegistered())
continue;
auto *Expr = Alias->getVariableValue();
if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) {
auto &Sym = cast<MCSymbolELF>(Inner->getSymbol());
if (Asm->registerSymbol(Sym))
Sym.setBinding(ELF::STB_WEAK);
}
}
}
// It is always valid to create a relocation with a symbol. It is preferable
@@ -1323,17 +1335,6 @@ void ELFObjectWriter::recordRelocation(const MCFragment &F,
MCContext &Ctx = getContext();
const auto *SymA = cast_or_null<MCSymbolELF>(Target.getAddSym());
bool ViaWeakRef = false;
if (SymA && SymA->isVariable()) {
const MCExpr *Expr = SymA->getVariableValue();
if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) {
if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) {
SymA = cast<MCSymbolELF>(&Inner->getSymbol());
ViaWeakRef = true;
}
}
}
const MCSectionELF *SecA = (SymA && SymA->isInSection())
? cast<MCSectionELF>(&SymA->getSection())
: nullptr;
@@ -1393,10 +1394,7 @@ void ELFObjectWriter::recordRelocation(const MCFragment &F,
if (const MCSymbolELF *R = Renames.lookup(SymA))
SymA = R;
if (ViaWeakRef)
SymA->setIsWeakrefUsedInReloc();
else
SymA->setUsedInReloc();
SymA->setUsedInReloc();
}
}
Relocations[&FixupSection].emplace_back(FixupOffset, SymA, Type, Addend);

View File

@@ -112,11 +112,16 @@ void MCELFStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
Asm.registerSymbol(*Section->getBeginSymbol());
}
void MCELFStreamer::emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {
getAssembler().registerSymbol(*Symbol);
const MCExpr *Value = MCSymbolRefExpr::create(
Symbol, MCSymbolRefExpr::VK_WEAKREF, getContext());
Alias->setVariableValue(Value);
void MCELFStreamer::emitWeakReference(MCSymbol *Alias, const MCSymbol *Target) {
auto *A = cast<MCSymbolELF>(Alias);
if (A->isDefined()) {
getContext().reportError(getStartTokLoc(), "symbol '" + A->getName() +
"' is already defined");
return;
}
A->setVariableValue(MCSymbolRefExpr::create(Target, getContext()));
A->setIsWeakref();
getWriter().Weakrefs.push_back(A);
}
// When GNU as encounters more than one .type declaration for an object it seems

View File

@@ -478,12 +478,7 @@ 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) {
if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF)
return false;
}
Sym.getVariableValue(true);
if (InSet)
return true;

View File

@@ -278,8 +278,8 @@ void MCObjectStreamer::emitSLEB128Value(const MCExpr *Value) {
}
void MCObjectStreamer::emitWeakReference(MCSymbol *Alias,
const MCSymbol *Symbol) {
report_fatal_error("This file format doesn't support weak aliases.");
const MCSymbol *Target) {
reportFatalUsageError("this file format doesn't support weak aliases");
}
void MCObjectStreamer::changeSection(MCSection *Section, uint32_t Subsection) {

View File

@@ -30,7 +30,7 @@ enum {
ELF_IsSignature_Shift = 10,
// One bit.
ELF_WeakrefUsedInReloc_Shift = 11,
ELF_Weakref_Shift = 11,
// One bit.
ELF_BindingSet_Shift = 12,
@@ -84,8 +84,6 @@ unsigned MCSymbolELF::getBinding() const {
return ELF::STB_LOCAL;
if (isUsedInReloc())
return ELF::STB_GLOBAL;
if (isWeakrefUsedInReloc())
return ELF::STB_WEAK;
if (isSignature())
return ELF::STB_LOCAL;
return ELF::STB_GLOBAL;
@@ -170,13 +168,13 @@ unsigned MCSymbolELF::getOther() const {
return Other << 5;
}
void MCSymbolELF::setIsWeakrefUsedInReloc() const {
uint32_t OtherFlags = getFlags() & ~(0x1 << ELF_WeakrefUsedInReloc_Shift);
setFlags(OtherFlags | (1 << ELF_WeakrefUsedInReloc_Shift));
void MCSymbolELF::setIsWeakref() const {
uint32_t OtherFlags = getFlags() & ~(0x1 << ELF_Weakref_Shift);
setFlags(OtherFlags | (1 << ELF_Weakref_Shift));
}
bool MCSymbolELF::isWeakrefUsedInReloc() const {
return getFlags() & (0x1 << ELF_WeakrefUsedInReloc_Shift);
bool MCSymbolELF::isWeakref() const {
return getFlags() & (0x1 << ELF_Weakref_Shift);
}
void MCSymbolELF::setIsSignature() const {

View File

@@ -70,14 +70,6 @@ void MCWasmStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
Asm.registerSymbol(*Section->getBeginSymbol());
}
void MCWasmStreamer::emitWeakReference(MCSymbol *Alias,
const MCSymbol *Symbol) {
getAssembler().registerSymbol(*Symbol);
const MCExpr *Value = MCSymbolRefExpr::create(
Symbol, MCSymbolRefExpr::VK_WEAKREF, getContext());
Alias->setVariableValue(Value);
}
bool MCWasmStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
assert(Attribute != MCSA_IndirectSymbol && "indirect symbols not supported");

View File

@@ -525,13 +525,6 @@ void WasmObjectWriter::recordRelocation(const MCFragment &F,
return;
}
if (SymA->isVariable()) {
const MCExpr *Expr = SymA->getVariableValue();
if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr))
if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF)
llvm_unreachable("weakref used in reloc not yet implemented");
}
// Put any constant offset in an addend. Offsets can be negative, and
// LLVM expects wrapping, in contrast to wasm's immediates which can't
// be negative and don't wrap.

View File

@@ -1,4 +1,5 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s | llvm-readelf -s - | FileCheck %s
# RUN: not llvm-mc -filetype=obj -triple=x86_64 --defsym ERR=1 %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:
// This is a long test that checks that the aliases created by weakref are
// never in the symbol table and that the only case it causes a symbol to
@@ -12,17 +13,18 @@
# CHECK-NEXT: 3: 0000000000000018 0 NOTYPE LOCAL DEFAULT 2 bar7
# CHECK-NEXT: 4: 000000000000001c 0 NOTYPE LOCAL DEFAULT 2 bar8
# CHECK-NEXT: 5: 0000000000000020 0 NOTYPE LOCAL DEFAULT 2 bar9
# CHECK-NEXT: 6: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND bar1
# CHECK-NEXT: 7: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND bar2
# CHECK-NEXT: 8: 0000000000000000 0 NOTYPE WEAK DEFAULT UND bar3
# CHECK-NEXT: 9: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND bar4
# CHECK-NEXT: 10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND bar5
# CHECK-NEXT: 11: 0000000000000028 0 NOTYPE GLOBAL DEFAULT 2 bar10
# CHECK-NEXT: 12: 0000000000000030 0 NOTYPE GLOBAL DEFAULT 2 bar11
# CHECK-NEXT: 13: 0000000000000030 0 NOTYPE GLOBAL DEFAULT 2 bar12
# CHECK-NEXT: 14: 0000000000000034 0 NOTYPE GLOBAL DEFAULT 2 bar13
# CHECK-NEXT: 15: 0000000000000038 0 NOTYPE GLOBAL DEFAULT 2 bar14
# CHECK-NEXT: 16: 0000000000000040 0 NOTYPE GLOBAL DEFAULT 2 bar15
# CHECK-NEXT: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND bar2
# CHECK-NEXT: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND bar4
# CHECK-NEXT: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND bar5
# CHECK-NEXT: 0000000000000028 0 NOTYPE GLOBAL DEFAULT 2 bar10
# CHECK-NEXT: 0000000000000030 0 NOTYPE GLOBAL DEFAULT 2 bar11
# CHECK-NEXT: 0000000000000030 0 NOTYPE GLOBAL DEFAULT 2 bar12
# CHECK-NEXT: 0000000000000034 0 NOTYPE GLOBAL DEFAULT 2 bar13
# CHECK-NEXT: 0000000000000038 0 NOTYPE GLOBAL DEFAULT 2 bar14
# CHECK-NEXT: 0000000000000040 0 NOTYPE GLOBAL DEFAULT 2 bar15
# CHECK-NEXT: 0000000000000000 0 NOTYPE WEAK DEFAULT UND bar3
# CHECK-NEXT: 0000000000000000 0 NOTYPE WEAK DEFAULT UND bar16
# CHECK-EMPTY:
.weakref foo1, bar1
@@ -87,3 +89,20 @@ bar15:
.weakref foo15, bar15
.long bar15
.long foo15
.long foo16
.weakref foo16, bar16
.ifdef ERR
alias:
.weakref alias, target
# ERR: [[#@LINE-1]]:1: error: symbol 'alias' is already defined
.set alias1, 1
.weakref alias1, target
# ERR: [[#@LINE-1]]:1: error: symbol 'alias1' is already defined
.weakref alias2, target
.set alias2, 1
.endif