[llvm] [SystemZ][z/OS] Use a function descriptor for external functions in initializers (PR #226682)

MMS IT GmbH via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 26 04:47:51 PDT 2026


https://github.com/mms-it-ch created https://github.com/llvm/llvm-project/pull/226682

The address of an external function in a static initializer was emitted as a V-con, i.e. the entry point, while an XPLINK function pointer must point to a function descriptor. A call through such a pointer loads the environment and entry point from the machine code of the function. Create a descriptor in the ADA for external functions as well, as is already done for internal functions and for constructor/destructor lists (`emitXXStructorList`).

`zos-lower-constant.ll` is updated: the pointer to the external function `bar` now points to its descriptor in the ADA.

A minimal program (`int (*p)(void) = ext;` called from `main`) ended with S0C6 at address `0707070707070707` on z/OS 3.1; with this change it returns the expected value.

Tests: `llvm-lit test/CodeGen/SystemZ test/MC/SystemZ test/MC/GOFF` passes (1303 passed, 19 unsupported).

Fixes #226658.

Assisted-by: Claude Code (Anthropic)

🤖 Generated with [Claude Code](https://claude.com/claude-code)


>From 6de8c85ca5dc4d5c4cdefdee3e580adfbc6b26b1 Mon Sep 17 00:00:00 2001
From: mms-it-ch <info at mms-it.ch>
Date: Sat, 26 Sep 2026 13:38:36 +0200
Subject: [PATCH] [SystemZ][z/OS] Use a function descriptor for external
 functions in initializers

The address of an external function in a static initializer was emitted as a
V-con, i.e. the entry point, while a function pointer must point to a function
descriptor. Use a descriptor in the ADA as for internal functions.

Fixes #226658

Assisted-by: Claude Code (Anthropic)
---
 llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp | 8 +++-----
 llvm/test/CodeGen/SystemZ/zos-lower-constant.ll     | 5 ++++-
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
index 3ab3dfc4a0bcb..7e69a53838262 100644
--- a/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
@@ -775,11 +775,9 @@ const MCExpr *SystemZXPLINKAsmPrinter::lowerConstant(const Constant *CV,
 
   if (IsFunc) {
     OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
-    if (FV->hasExternalLinkage())
-      return MCSpecifierExpr::create(MCSymbolRefExpr::create(Sym, OutContext),
-                                     SystemZ::S_VCon, OutContext);
-    // Trigger creation of function descriptor in ADA for internal
-    // functions.
+    // A function pointer must point to a function descriptor. Trigger
+    // creation of a function descriptor in the ADA, for internal and external
+    // functions alike (a V-con would yield the entry point instead).
     unsigned Disp = ADATable.insert(Sym, SystemZII::MO_ADA_DIRECT_FUNC_DESC);
     return MCBinaryExpr::createAdd(
         MCSpecifierExpr::create(
diff --git a/llvm/test/CodeGen/SystemZ/zos-lower-constant.ll b/llvm/test/CodeGen/SystemZ/zos-lower-constant.ll
index 64a51f8e43582..61d4653540d59 100644
--- a/llvm/test/CodeGen/SystemZ/zos-lower-constant.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-lower-constant.ll
@@ -5,9 +5,12 @@
 ; CHECK: func_s CSECT
 ; CHECK: DC AD(AD({{.*}}#S)+XL8'0')
 ; CHECK: func_e CSECT
-; CHECK: DC VD(bar)
+; CHECK: DC AD(AD({{.*}}#S)+XL8'16')
 ; CHECK: DC RD(foo)
 ; CHECK-NEXT: DC VD(foo)
+; CHECK-NEXT: * Offset 16 function descriptor of bar
+; CHECK-NEXT: DC RD(bar)
+; CHECK-NEXT: DC VD(bar)
 @x = hidden global i32 4077, align 4
 @y = hidden global ptr @x, align 8
 @func_s = hidden global ptr @foo, align 8



More information about the llvm-commits mailing list