[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