[llvm] [SystemZ][z/OS] Handle constants with initializers with relocations (PR #223055)
Kai Nacke via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 11 13:51:42 PDT 2026
https://github.com/redstar created https://github.com/llvm/llvm-project/pull/223055
When the initializer of a constant needs relocations, the constant cannot be placed into the code section, because the loader needs a writable section to fixup the relocation.
This change
- sets the relocation model for z/OS to `DynamicNoPIC`, which better fits the relocation handling than `Static`, and
- treats section kind `ReadOnlyWithRel` like a variable.
Assisted by IBM Bob.
>From e03e9ee4567c8ab9e189405410d2fae1734d10f8 Mon Sep 17 00:00:00 2001
From: Kai Nacke <kai.peter.nacke at ibm.com>
Date: Fri, 11 Sep 2026 16:46:12 -0400
Subject: [PATCH] [SystemZ][z/OS] Handle constants with initializers with
relocations
When the initializer of a constant needs relocations, the constant
cannot be placed into the code section, because the loader needs
a writable section to fixup the relocation.
This change
- sets the relocation model for z/OS to `DynamicNoPIC`, which better
fits the relocation handling than `Static`, and
- treats section kind `ReadOnlyWithRel` like a variable.
---
.../CodeGen/TargetLoweringObjectFileImpl.cpp | 2 +-
.../Target/SystemZ/SystemZTargetMachine.cpp | 21 +++++++++++----
.../SystemZ/zos-section-readonlywithrel.ll | 27 +++++++++++++++++++
3 files changed, 44 insertions(+), 6 deletions(-)
create mode 100644 llvm/test/CodeGen/SystemZ/zos-section-readonlywithrel.ll
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 2fb44041c164e..9f7a038374792 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -2893,7 +2893,7 @@ MCSection *TargetLoweringObjectFileGOFF::SelectSectionForGlobal(
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
auto *Symbol = TM.getSymbol(GO);
- if (Kind.isBSS() || Kind.isData()) {
+ if (Kind.isBSS() || Kind.isData() || Kind.isReadOnlyWithRel()) {
GOFF::ESDBindingScope PRBindingScope =
GO->hasExternalLinkage()
? (GO->hasDefaultVisibility() ? GOFF::ESD_BSC_ImportExport
diff --git a/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp b/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp
index 5158077716d9f..ccf3b07b0bfab 100644
--- a/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp
@@ -68,9 +68,20 @@ static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
return std::make_unique<SystemZELFTargetObjectFile>();
}
-static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) {
- // Static code is suitable for use in a dynamic executable; there is no
- // separate DynamicNoPIC model.
+static Reloc::Model getEffectiveRelocModel(const Triple &TT,
+ std::optional<Reloc::Model> RM) {
+ if (TT.isOSzOS()) {
+ // On z/OS, constant globals whose initializers contain pointer relocations
+ // (e.g. vtables) must be placed in a writable section (C_WSA64) so the
+ // GOFF binder can apply them at link time. Using DynamicNoPIC causes
+ // getKindForGlobal() to classify such globals as ReadOnlyWithRel instead
+ // of ReadOnly, which routes them to C_WSA64 rather than C_CODE64.
+ if (!RM || *RM == Reloc::DynamicNoPIC)
+ return Reloc::DynamicNoPIC;
+ return *RM;
+ }
+ // For ELF/Linux, static code is suitable for use in a dynamic executable;
+ // there is no separate DynamicNoPIC model.
if (!RM || *RM == Reloc::DynamicNoPIC)
return Reloc::Static;
return *RM;
@@ -128,8 +139,8 @@ SystemZTargetMachine::SystemZTargetMachine(const Target &T, const Triple &TT,
CodeGenOptLevel OL, bool JIT)
: CodeGenTargetMachineImpl(
T, TT.computeDataLayout(), TT, CPU, FS, Options,
- getEffectiveRelocModel(RM),
- getEffectiveSystemZCodeModel(CM, getEffectiveRelocModel(RM), JIT),
+ getEffectiveRelocModel(TT, RM),
+ getEffectiveSystemZCodeModel(CM, getEffectiveRelocModel(TT, RM), JIT),
OL),
TLOF(createTLOF(getTargetTriple())) {
initAsmInfo();
diff --git a/llvm/test/CodeGen/SystemZ/zos-section-readonlywithrel.ll b/llvm/test/CodeGen/SystemZ/zos-section-readonlywithrel.ll
new file mode 100644
index 0000000000000..5f856df3fc4ce
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/zos-section-readonlywithrel.ll
@@ -0,0 +1,27 @@
+; Test that a read-only global containing pointer relocations (e.g. a C++
+; vtable) is placed in the writable static area (C_WSA64) and NOT in the
+; constant/text section (C_CODE64) on z/OS.
+;
+; z/OS uses DynamicNoPIC as its effective relocation model. This causes
+; getKindForGlobal() to skip the Reloc::Static short-circuit and classify
+; constant globals that needsDynamicRelocation() as ReadOnlyWithRel instead
+; of ReadOnly. SelectSectionForGlobal then routes ReadOnlyWithRel to a
+; per-symbol C_WSA64 PR section (ESD_LB_Deferred) rather than C_CODE64
+; (ESD_LB_Initial, read-only/executable).
+;
+; RUN: llc < %s -mtriple=s390x-ibm-zos | FileCheck %s
+
+ at _ZTV4Base = hidden constant [2 x ptr] [ptr null, ptr @_ZTI4Base], align 8
+ at _ZTI4Base = external hidden global ptr
+
+; The vtable gets its own SD and a C_WSA64 ED (DEFLOAD, NOTEXECUTABLE).
+; CHECK: _ZTV4Base CSECT
+; CHECK-NEXT: C_WSA64 CATTR {{.*}}DEFLOAD,NOTEXECUTABLE
+; CHECK: _ZTV4Base XATTR LINKAGE(XPLINK),REFERENCE(DATA)
+
+; The vtable data (null + reloc to _ZTI4Base) appears inside the WSA section.
+; CHECK: DC XL8'0000000000000000'
+; CHECK-NEXT: DC AD(_ZTI4Base)
+
+; Crucially, the vtable must NOT be emitted directly inside C_CODE64.
+; CHECK-NOT: C_CODE64{{.*}}_ZTV4Base
More information about the llvm-commits
mailing list