[llvm] [SystemZ][z/OS] Keep weak references weak (PR #226840)

MMS IT GmbH via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 28 02:53:36 PDT 2026


https://github.com/mms-it-ch updated https://github.com/llvm/llvm-project/pull/226840

>From c737d5b34ad701809446d4c22fc8bd7d01297fbd Mon Sep 17 00:00:00 2001
From: mms-it-ch <info at mms-it.ch>
Date: Sun, 27 Sep 2026 23:37:55 +0200
Subject: [PATCH] [SystemZ][z/OS] Keep weak references weak

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, which never got the weak attribute of the
  function symbol. The attribute is already set when the ADA is emitted,
  because AsmPrinter::doFinalization emits the weak references before
  emitEndOfAsmFile.
- An external data reference is a part reference (PR). GOFF::PRAttr had
  no binding strength, and the PR constructor did not set it.

Without this change the binder reports IEW2456E for such references.

Fixes #226835.

Assisted-by: Claude Code (Anthropic)
---
 llvm/include/llvm/MC/MCGOFFAttributes.h       |  1 +
 llvm/lib/MC/GOFFObjectWriter.cpp              |  5 ++-
 .../SystemZ/SystemZXPLINKAsmPrinter.cpp       |  4 ++
 llvm/test/CodeGen/SystemZ/zos-extern-weak.ll  | 37 +++++++++++++++++++
 4 files changed, 45 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/SystemZ/zos-extern-weak.ll

diff --git a/llvm/include/llvm/MC/MCGOFFAttributes.h b/llvm/include/llvm/MC/MCGOFFAttributes.h
index 289d962e993b8..eb2abd4cf806b 100644
--- a/llvm/include/llvm/MC/MCGOFFAttributes.h
+++ b/llvm/include/llvm/MC/MCGOFFAttributes.h
@@ -77,6 +77,7 @@ struct PRAttr {
   GOFF::ESDLinkageType Linkage = GOFF::ESD_LT_XPLink;
   GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified;
   uint32_t SortKey = 0;
+  GOFF::ESDBindingStrength BindingStrength = GOFF::ESD_BST_Strong;
 };
 
 // Attributes for ER symbols.
diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp
index 36407759dbc50..435e144f828bd 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.getLinkage(), Symbol.getBindingScope(), 0,
+                               Symbol.getBindingStrength()});
     writeSymbol(PR);
   } else {
     GOFFSymbol ER(Symbol.getExternalName(), Symbol.getIndex(),
diff --git a/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
index 3ab3dfc4a0bcb..166185fa0967d 100644
--- a/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
@@ -341,6 +341,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