[llvm] 976a04b - [SystemZ][z/OS] Keep weak references weak (#226840)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 29 07:53:36 PDT 2026
Author: MMS IT GmbH
Date: 2026-09-29T10:53:29-04:00
New Revision: 976a04b549b3e91e51eb7676d86caa8c34a63571
URL: https://github.com/llvm/llvm-project/commit/976a04b549b3e91e51eb7676d86caa8c34a63571
DIFF: https://github.com/llvm/llvm-project/commit/976a04b549b3e91e51eb7676d86caa8c34a63571.diff
LOG: [SystemZ][z/OS] Keep weak references weak (#226840)
Fixes #226835.
An `extern_weak` reference must stay unresolved without an error when
the symbol does not exist. On z/OS two kinds of references were always
strong:
- Taking the address of an external function goes through the indirect
symbol `<name>@indirect` (ADA slot `MO_ADA_INDIRECT_FUNC_DESC`). It
never got the weak attribute of the function symbol. The weak attribute
is already set on the function symbol when the ADA is emitted, because
`AsmPrinter::doFinalization` emits the weak references before
`emitEndOfAsmFile`. So the indirect symbol now becomes a weak reference
too.
- An external data reference is a part reference (PR). `GOFF::PRAttr`
had no binding strength, and the PR constructor in `GOFFObjectWriter`
did not set it. `PRAttr` gets a `BindingStrength` field, and
`defineExtern` passes the strength of the symbol.
Without this change, a C program with `extern int wv
__attribute__((weak));` and `extern void wf(void)
__attribute__((weak));` that takes `&wv` and `wf` fails to bind on z/OS
3.1 (IEW2456E for `wv` and `wf`). With the change it binds, and at run
time both addresses are null, as on other targets.
Tests: new `zos-extern-weak.ll` checks `WXTRN wf at indirect` in the HLASM
output and the binding strength of the ER and PR symbols in the object
file. `llvm-lit test/CodeGen/SystemZ test/MC/SystemZ test/MC/GOFF`
passes (1304 passed, 19 unsupported). Without the fix, both checks of
the new test fail.
Found while porting Free Pascal to z/OS (`weakexternal`).
Assisted-by: Claude Code (Anthropic)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Added:
llvm/test/CodeGen/SystemZ/zos-extern-weak.ll
Modified:
llvm/include/llvm/MC/MCGOFFAttributes.h
llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
llvm/lib/MC/GOFFObjectWriter.cpp
llvm/lib/MC/MCObjectFileInfo.cpp
llvm/lib/MC/MCSymbolGOFF.cpp
llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/MC/MCGOFFAttributes.h b/llvm/include/llvm/MC/MCGOFFAttributes.h
index 289d962e993b8..4af5717fccfe6 100644
--- a/llvm/include/llvm/MC/MCGOFFAttributes.h
+++ b/llvm/include/llvm/MC/MCGOFFAttributes.h
@@ -74,6 +74,7 @@ struct LDAttr {
struct PRAttr {
bool IsRenamable = false;
GOFF::ESDExecutable Executable = GOFF::ESD_EXE_Unspecified;
+ GOFF::ESDBindingStrength BindingStrength = GOFF::ESD_BST_Strong;
GOFF::ESDLinkageType Linkage = GOFF::ESD_LT_XPLink;
GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified;
uint32_t SortKey = 0;
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 68ff80ae1d376..d47b35cfa7bcf 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -2913,11 +2913,11 @@ MCSection *TargetLoweringObjectFileGOFF::getSectionForLSDA(
GOFF::ESD_LB_Initial, GOFF::ESD_RQ_0, 0},
static_cast<MCSectionGOFF *>(TextSection)->getParent());
WSA->setAlignment(Align(4)); // Fullword
- return getContext().getGOFFSection(SectionKind::getData(), Name,
- GOFF::PRAttr{true, GOFF::ESD_EXE_DATA,
- GOFF::ESD_LT_XPLink,
- GOFF::ESD_BSC_Section, 0},
- WSA);
+ return getContext().getGOFFSection(
+ SectionKind::getData(), Name,
+ GOFF::PRAttr{true, GOFF::ESD_EXE_DATA, GOFF::ESD_BST_Strong,
+ GOFF::ESD_LT_XPLink, GOFF::ESD_BSC_Section, 0},
+ WSA);
}
MCSection *TargetLoweringObjectFileGOFF::SelectSectionForGlobal(
@@ -2950,8 +2950,8 @@ MCSection *TargetLoweringObjectFileGOFF::SelectSectionForGlobal(
ED->setAlignment(Alignment.value_or(llvm::Align(8)));
MCSectionGOFF *PR = getContext().getGOFFSection(
Kind, Symbol->getName(),
- GOFF::PRAttr{false, GOFF::ESD_EXE_DATA, GOFF::ESD_LT_XPLink,
- PRBindingScope, 0},
+ GOFF::PRAttr{false, GOFF::ESD_EXE_DATA, GOFF::ESD_BST_Strong,
+ GOFF::ESD_LT_XPLink, PRBindingScope, 0},
ED);
// The binder rejects zero-length PR sections. Mark the PR so the writer
// inflates it to a valid length if needed.
@@ -2987,8 +2987,8 @@ TargetLoweringObjectFileGOFF::getStaticXtorSection(unsigned Priority) const {
MCSectionGOFF *Xtor = Ctx.getGOFFSection(
SectionKind::getData(), Name,
- GOFF::PRAttr{true, GOFF::ESD_EXE_DATA, GOFF::ESD_LT_XPLink,
- GOFF::ESD_BSC_Section, Prio},
+ GOFF::PRAttr{true, GOFF::ESD_EXE_DATA, GOFF::ESD_BST_Strong,
+ GOFF::ESD_LT_XPLink, GOFF::ESD_BSC_Section, Prio},
SInit);
return Xtor;
}
diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp
index 36407759dbc50..9593375e957e8 100644
--- a/llvm/lib/MC/GOFFObjectWriter.cpp
+++ b/llvm/lib/MC/GOFFObjectWriter.cpp
@@ -265,6 +265,7 @@ class GOFFSymbol {
SymbolType(GOFF::ESD_ST_PartReference), NameSpace(EDAttr.NameSpace) {
SymbolFlags.setRenameable(Attr.IsRenamable);
BehavAttrs.setExecutable(Attr.Executable);
+ BehavAttrs.setBindingStrength(Attr.BindingStrength);
BehavAttrs.setLinkageType(Attr.Linkage);
BehavAttrs.setBindingScope(Attr.BindingScope);
BehavAttrs.setAlignment(Alignment);
@@ -401,8 +402,8 @@ void GOFFWriter::defineExtern(const MCSymbolGOFF &Symbol) {
GOFFSymbol PR(Symbol.getExternalName(), Symbol.getIndex(), ED->getOrdinal(),
ED->getEDAttributes(), ED->getEDAlignment(),
GOFF::PRAttr{/*IsRenamable*/ false, Symbol.getCodeData(),
- Symbol.getLinkage(), Symbol.getBindingScope(),
- 0});
+ Symbol.getBindingStrength(), Symbol.getLinkage(),
+ Symbol.getBindingScope(), 0});
writeSymbol(PR);
} else {
GOFFSymbol ER(Symbol.getExternalName(), Symbol.getIndex(),
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 5dd5a63fda9cf..41e5adf304d35 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -584,11 +584,11 @@ void MCObjectFileInfo::initGOFFMCObjectFileInfo(const Triple &T) {
GOFF::ESD_LB_Deferred, GOFF::ESD_RQ_1, 0},
RootSDSection);
ADAEDSection->setAlignment(Align(16)); // Quadword
- ADASection = Ctx->getGOFFSection(SectionKind::getData(), "#S",
- GOFF::PRAttr{false, GOFF::ESD_EXE_DATA,
- GOFF::ESD_LT_XPLink,
- GOFF::ESD_BSC_Section, 0},
- ADAEDSection);
+ ADASection = Ctx->getGOFFSection(
+ SectionKind::getData(), "#S",
+ GOFF::PRAttr{false, GOFF::ESD_EXE_DATA, GOFF::ESD_BST_Strong,
+ GOFF::ESD_LT_XPLink, GOFF::ESD_BSC_Section, 0},
+ ADAEDSection);
TextSection = Ctx->getGOFFSection(
SectionKind::getText(), GOFF::CLASS_CODE,
@@ -605,11 +605,11 @@ void MCObjectFileInfo::initGOFFMCObjectFileInfo(const Triple &T) {
GOFF::ESD_LB_Initial, GOFF::ESD_RQ_0, 0},
RootSDSection);
PPA2ListEDSection->setAlignment(Align(8)); // Doubleword
- PPA2ListSection = Ctx->getGOFFSection(SectionKind::getData(), ".&ppa2",
- GOFF::PRAttr{true, GOFF::ESD_EXE_DATA,
- GOFF::ESD_LT_OS,
- GOFF::ESD_BSC_Section, 0},
- PPA2ListEDSection);
+ PPA2ListSection = Ctx->getGOFFSection(
+ SectionKind::getData(), ".&ppa2",
+ GOFF::PRAttr{true, GOFF::ESD_EXE_DATA, GOFF::ESD_BST_Strong,
+ GOFF::ESD_LT_OS, GOFF::ESD_BSC_Section, 0},
+ PPA2ListEDSection);
IDRLSection = Ctx->getGOFFSection(
SectionKind::getData(), "B_IDRL",
diff --git a/llvm/lib/MC/MCSymbolGOFF.cpp b/llvm/lib/MC/MCSymbolGOFF.cpp
index 31ec70cc74c2a..43939f8f407b5 100644
--- a/llvm/lib/MC/MCSymbolGOFF.cpp
+++ b/llvm/lib/MC/MCSymbolGOFF.cpp
@@ -28,11 +28,11 @@ MCSectionGOFF *MCSymbolGOFF::getSectionForCommonSymbol(MCContext &Ctx,
SD);
ED->setAlignment(ByteAlignment);
- return Ctx.getGOFFSection(SectionKind::getBSS(), getName(),
- GOFF::PRAttr{false, GOFF::ESD_EXE_DATA,
- GOFF::ESD_LT_XPLink, getBindingScope(),
- 0},
- ED);
+ return Ctx.getGOFFSection(
+ SectionKind::getBSS(), getName(),
+ GOFF::PRAttr{false, GOFF::ESD_EXE_DATA, GOFF::ESD_BST_Strong,
+ GOFF::ESD_LT_XPLink, getBindingScope(), 0},
+ ED);
}
bool MCSymbolGOFF::setSymbolAttribute(MCSymbolAttr Attribute) {
diff --git a/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
index 47703b152c8da..60fd1fce1440d 100644
--- a/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
@@ -340,6 +340,10 @@ void SystemZXPLINKAsmPrinter::emitADASection() {
OutStreamer->emitSymbolAttribute(Alias, MCSA_Extern);
MCSymbolGOFF *GOFFSym =
static_cast<llvm::MCSymbolGOFF *>(const_cast<llvm::MCSymbol *>(Sym));
+ // A weak reference (extern_weak) stays weak through the indirect
+ // symbol, otherwise the binder fails on the unresolved reference.
+ if (GOFFSym->isWeak())
+ OutStreamer->emitSymbolAttribute(Alias, MCSA_WeakReference);
ZOS->emitExternalName(Alias, GOFFSym->getExternalName());
EMIT_COMMENT("pointer to function descriptor");
OutStreamer->emitValue(
diff --git a/llvm/test/CodeGen/SystemZ/zos-extern-weak.ll b/llvm/test/CodeGen/SystemZ/zos-extern-weak.ll
new file mode 100644
index 0000000000000..d8b1d1e9789f7
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/zos-extern-weak.ll
@@ -0,0 +1,37 @@
+; Weak references (extern_weak) must be weak in the object file: the indirect
+; symbol through which the address of a function is taken, and the part
+; reference for external data. Otherwise the binder fails when the symbol
+; does not exist.
+; RUN: llc < %s -mtriple=s390x-ibm-zos | FileCheck %s
+; RUN: llc < %s -mtriple=s390x-ibm-zos --filetype=obj | \
+; RUN: od -Ax -tx1 -v | FileCheck --check-prefix=CHECKOBJ --ignore-case %s
+
+; CHECK-DAG: WXTRN wf at indirect
+; CHECK-DAG: WXTRN wf{{ *$}}
+; CHECK-NOT: {{^ EXTRN wf}}
+
+; The last bytes of the ESD records: behavioral attributes 4-9 (binding
+; strength 1 = weak in byte 4), name length and name.
+; PR wv (external data):
+; CHECKOBJ: {{^[0-9a-f]+}} 01 04 24 00 00 00 00 02 a6 a5
+; ER wf at indirect (external name wf, indirect reference):
+; CHECKOBJ: {{^[0-9a-f]+}} 01 14 20 00 00 00 00 02 a6 86
+; ER wf:
+; CHECKOBJ: {{^[0-9a-f]+}} 01 04 20 00 00 00 00 02 a6 86
+
+ at wv = extern_weak global i32
+
+declare extern_weak void @wf()
+
+define ptr @getv() {
+ ret ptr @wv
+}
+
+define ptr @getf() {
+ ret ptr @wf
+}
+
+define void @callf() {
+ call void @wf()
+ ret void
+}
More information about the llvm-commits
mailing list