[llvm-branch-commits] [llvm] [SystemZ] Implement ctor/dtor emission via @@SQINIT and .xtor sections (PR #171476)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Dec 9 09:08:12 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-mc
Author: Amy Kwan (amy-kwan)
<details>
<summary>Changes</summary>
This patch implements support for constructors/destructors by introducing the
`@@<!-- -->SQINIT` section and emitting `.xtor.<priority>` sections within the SystemZ
AsmPrinter and in the GOFF object lowering layer. Improvements to ADA descriptor
handling is also done within this change.
---
Full diff: https://github.com/llvm/llvm-project/pull/171476.diff
7 Files Affected:
- (modified) llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h (+4)
- (modified) llvm/include/llvm/MC/MCGOFFAttributes.h (+1)
- (modified) llvm/include/llvm/MC/MCSectionGOFF.h (+12)
- (modified) llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp (+49)
- (modified) llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp (+79-10)
- (modified) llvm/lib/Target/SystemZ/SystemZAsmPrinter.h (+9-5)
- (added) llvm/test/CodeGen/SystemZ/zos_sinit.ll (+36)
``````````diff
diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
index fe450b3c1a3a2..8f1f20f7ead0c 100644
--- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
+++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
@@ -331,6 +331,10 @@ class TargetLoweringObjectFileGOFF : public TargetLoweringObjectFile {
const TargetMachine &TM) const override;
MCSection *getSectionForLSDA(const Function &F, const MCSymbol &FnSym,
const TargetMachine &TM) const override;
+ MCSection *getStaticCtorSection(unsigned Priority,
+ const MCSymbol *KeySym) const override;
+ MCSection *getStaticDtorSection(unsigned Priority,
+ const MCSymbol *KeySym) const override;
};
} // end namespace llvm
diff --git a/llvm/include/llvm/MC/MCGOFFAttributes.h b/llvm/include/llvm/MC/MCGOFFAttributes.h
index e771f36f35346..b1c6d73e41f9f 100644
--- a/llvm/include/llvm/MC/MCGOFFAttributes.h
+++ b/llvm/include/llvm/MC/MCGOFFAttributes.h
@@ -94,6 +94,7 @@ constexpr StringLiteral CLASS_CODE = "C_CODE64";
constexpr StringLiteral CLASS_WSA = "C_WSA64";
constexpr StringLiteral CLASS_DATA = "C_DATA64";
constexpr StringLiteral CLASS_PPA2 = "C_@@QPPA2";
+constexpr StringLiteral CLASS_SINIT = "C_@@SQINIT";
} // namespace GOFF
} // namespace llvm
diff --git a/llvm/include/llvm/MC/MCSectionGOFF.h b/llvm/include/llvm/MC/MCSectionGOFF.h
index 2136148368fbd..261bee5e57d96 100644
--- a/llvm/include/llvm/MC/MCSectionGOFF.h
+++ b/llvm/include/llvm/MC/MCSectionGOFF.h
@@ -27,6 +27,13 @@ namespace llvm {
class MCExpr;
class LLVM_ABI MCSectionGOFF final : public MCSection {
+public:
+ enum XtorType { NotXtor, CtorType, DtorType };
+
+private:
+ // ctor/dtor section related - i.e. C_@@S[Q]INIT
+ enum XtorType XtorSectionType = NotXtor;
+
// Parent of this section. Implies that the parent is emitted first.
MCSectionGOFF *Parent;
@@ -115,6 +122,11 @@ class LLVM_ABI MCSectionGOFF final : public MCSection {
bool requiresNonZeroLength() const { return RequiresNonZeroLength; }
void setName(StringRef SectionName) { Name = SectionName; }
+
+ bool isXtorSection() const { return XtorSectionType != NotXtor; }
+ void setXtorSectionType(XtorType Value) { XtorSectionType = Value; }
+ XtorType getXtorSectionType() const { return XtorSectionType; }
+
};
} // end namespace llvm
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 5edbc4caf3fae..4ede966702335 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -2794,6 +2794,10 @@ void TargetLoweringObjectFileGOFF::getModuleMetadata(Module &M) {
TextLD->setWeak(false);
TextLD->setADA(ADAPR);
TextSection->setBeginSymbol(TextLD);
+ // Initialize the label for the ADA section.
+ MCSymbolGOFF *ADASym = static_cast<MCSymbolGOFF *>(
+ getContext().getOrCreateSymbol(ADAPR->getName()));
+ ADAPR->setBeginSymbol(ADASym);
}
MCSection *TargetLoweringObjectFileGOFF::getExplicitSectionGlobal(
@@ -2857,3 +2861,48 @@ MCSection *TargetLoweringObjectFileGOFF::SelectSectionForGlobal(
}
return TextSection;
}
+
+static MCSectionGOFF *getStaticStructorSectionGOFF(MCContext &Ctx,
+ const MCSection *TextSection,
+ bool IsCtor,
+ unsigned Priority) {
+ // xl compilers on z/OS support priorities from min-int to max-int, with
+ // sinit as source priority 0. For clang, sinit has source priority 65535.
+ // For GOFF, the priority sortkey field is an unsigned value. So, we
+ // add min-int to get sorting to work properly but also subtract the
+ // clang sinit (65535) value so internally xl sinit and clang sinit have
+ // the same unsigned GOFF priority sortkey field value (i.e. 0x80000000).
+ static constexpr const uint32_t ClangDefaultSinitPriority = 65535;
+ uint32_t Prio = Priority + (0x80000000 - ClangDefaultSinitPriority);
+
+ std::string Name(".xtor");
+ if (Priority != ClangDefaultSinitPriority)
+ Name = llvm::Twine(Name).concat(".").concat(llvm::utostr(Priority)).str();
+
+ MCSectionGOFF *SInit = Ctx.getGOFFSection(
+ SectionKind::getMetadata(), GOFF::CLASS_SINIT,
+ GOFF::EDAttr{false, GOFF::ESD_RMODE_64, GOFF::ESD_NS_Parts,
+ GOFF::ESD_TS_ByteOriented, GOFF::ESD_BA_Merge,
+ GOFF::ESD_LB_Initial, GOFF::ESD_RQ_0,
+ GOFF::ESD_ALIGN_Doubleword},
+ static_cast<const MCSectionGOFF *>(TextSection)->getParent());
+
+ MCSectionGOFF *Xtor = Ctx.getGOFFSection(
+ SectionKind::getData(), Name,
+ GOFF::PRAttr{true, GOFF::ESD_EXE_DATA, GOFF::ESD_LT_XPLink,
+ GOFF::ESD_BSC_Section, Prio},
+ SInit);
+ return Xtor;
+}
+
+MCSection *TargetLoweringObjectFileGOFF::getStaticCtorSection(
+ unsigned Priority, const MCSymbol *KeySym) const {
+ return getStaticStructorSectionGOFF(getContext(), TextSection, true,
+ Priority);
+}
+
+MCSection *TargetLoweringObjectFileGOFF::getStaticDtorSection(
+ unsigned Priority, const MCSymbol *KeySym) const {
+ return getStaticStructorSectionGOFF(getContext(), TextSection, false,
+ Priority);
+}
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 414d68e2678ed..5d43eb0830746 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -31,6 +31,7 @@
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbolGOFF.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/Compiler.h"
@@ -170,13 +171,14 @@ void SystemZAsmPrinter::emitCallInformation(CallType CT) {
.addReg(SystemZMC::GR64Regs[static_cast<unsigned>(CT)]));
}
-uint32_t SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MCSymbol *Sym,
- unsigned SlotKind) {
+std::pair<const MCSymbol *, uint32_t>
+SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MCSymbol *Sym,
+ unsigned SlotKind) {
auto Key = std::make_pair(Sym, SlotKind);
- auto It = Displacements.find(Key);
+ auto *It = Displacements.find(Key);
if (It != Displacements.end())
- return (*It).second;
+ return std::pair(Sym, (*It).second);
// Determine length of descriptor.
uint32_t Length;
@@ -189,18 +191,23 @@ uint32_t SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MCSymbol *Sym,
break;
}
+ // Language Environment DLL logic requires function descriptors, for
+ // imported functions, that are placed in the ADA to be 8 byte aligned.
+ if (SlotKind == SystemZII::MO_ADA_DIRECT_FUNC_DESC)
+ NextDisplacement = alignTo(NextDisplacement, 8);
uint32_t Displacement = NextDisplacement;
Displacements[std::make_pair(Sym, SlotKind)] = NextDisplacement;
NextDisplacement += Length;
- return Displacement;
+ return std::pair(Sym, Displacement);
}
-uint32_t
+std::pair<const MCSymbol *, uint32_t>
SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MachineOperand MO) {
MCSymbol *Sym;
if (MO.getType() == MachineOperand::MO_GlobalAddress) {
const GlobalValue *GV = MO.getGlobal();
+ assert(GV->hasName() && "Cannot put unnamed value in ADA");
Sym = MO.getParent()->getMF()->getTarget().getSymbol(GV);
assert(Sym && "No symbol");
} else if (MO.getType() == MachineOperand::MO_ExternalSymbol) {
@@ -347,7 +354,9 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
case SystemZ::ADA_ENTRY: {
const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
const SystemZInstrInfo *TII = Subtarget.getInstrInfo();
- uint32_t Disp = ADATable.insert(MI->getOperand(1));
+ const MCSymbol *Sym;
+ uint32_t Disp;
+ std::tie(Sym, Disp) = ADATable.insert(MI->getOperand(1));
Register TargetReg = MI->getOperand(0).getReg();
Register ADAReg = MI->getOperand(2).getReg();
@@ -1012,6 +1021,60 @@ void SystemZAsmPrinter::emitMachineConstantPoolValue(
OutStreamer->emitValue(Expr, Size);
}
+// Emit the ctor or dtor list taking into account the init priority.
+void SystemZAsmPrinter::emitXXStructorList(const DataLayout &DL,
+ const Constant *List,
+ bool IsCtor) {
+ if (TM.getTargetTriple().isOSBinFormatGOFF())
+ AsmPrinter::emitXXStructorList(DL, List, IsCtor);
+
+ SmallVector<Structor, 8> Structors;
+ preprocessXXStructorList(DL, List, Structors);
+ if (Structors.empty())
+ return;
+
+ const Align Align = llvm::Align(4);
+ const TargetLoweringObjectFile &Obj = getObjFileLowering();
+ for (Structor &S : Structors) {
+ MCSection *OutputSection =
+ (IsCtor ? Obj.getStaticCtorSection(S.Priority, nullptr)
+ : Obj.getStaticDtorSection(S.Priority, nullptr));
+ OutStreamer->switchSection(OutputSection);
+ if (OutStreamer->getCurrentSection() != OutStreamer->getPreviousSection())
+ emitAlignment(Align);
+
+ const MCSectionGOFF *Section =
+ static_cast<const MCSectionGOFF *>(getCurrentSection());
+ uint32_t XtorPriority = Section->getPRAttributes().SortKey;
+
+ const GlobalValue *GV = dyn_cast<GlobalValue>(S.Func->stripPointerCasts());
+ assert(GV && "C++ xxtor pointer was not a GlobalValue!");
+ MCSymbolGOFF *Symbol = static_cast<MCSymbolGOFF *>(getSymbol(GV));
+
+ // @@SQINIT entry: { unsigned prio; void (*ctor)(); void (*dtor)(); }
+
+ unsigned PointerSizeInBytes = DL.getPointerSize();
+
+ auto &Ctx = OutStreamer->getContext();
+ const MCExpr *ADAFuncRefExpr;
+ unsigned SlotKind = SystemZII::MO_ADA_DIRECT_FUNC_DESC;
+ ADAFuncRefExpr = MCBinaryExpr::createAdd(
+ MCSpecifierExpr::create(MCSymbolRefExpr::create(ADASym, OutContext),
+ SystemZ::S_QCon, OutContext),
+ MCConstantExpr::create(ADATable.insert(Symbol, SlotKind).second, Ctx),
+ Ctx);
+
+ emitInt32(XtorPriority);
+ if (IsCtor) {
+ OutStreamer->emitValue(ADAFuncRefExpr, PointerSizeInBytes);
+ OutStreamer->emitIntValue(0, PointerSizeInBytes);
+ } else {
+ OutStreamer->emitIntValue(0, PointerSizeInBytes);
+ OutStreamer->emitValue(ADAFuncRefExpr, PointerSizeInBytes);
+ }
+ }
+}
+
static void printFormattedRegName(const MCAsmInfo *MAI, unsigned RegNo,
raw_ostream &OS) {
const char *RegName;
@@ -1536,13 +1599,17 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) {
OutStreamer->AddComment("Flags");
OutStreamer->emitInt32(0); // LSDA field is a WAS offset
OutStreamer->AddComment("Personality routine");
- OutStreamer->emitInt64(ADATable.insert(
- PersonalityRoutine, SystemZII::MO_ADA_INDIRECT_FUNC_DESC));
+ // Store only offset of function descriptor
+ OutStreamer->emitInt64(
+ ADATable
+ .insert(PersonalityRoutine, SystemZII::MO_ADA_INDIRECT_FUNC_DESC)
+ .second);
OutStreamer->AddComment("LSDA location");
+ // Store only offset of LSDA
MCSymbol *GCCEH = MF->getContext().getOrCreateSymbol(
Twine("GCC_except_table") + Twine(MF->getFunctionNumber()));
OutStreamer->emitInt64(
- ADATable.insert(GCCEH, SystemZII::MO_ADA_DATA_SYMBOL_ADDR));
+ ADATable.insert(GCCEH, SystemZII::MO_ADA_DATA_SYMBOL_ADDR).second);
}
// Emit name length and name optional section (0x01 of flags 4)
@@ -1561,6 +1628,8 @@ void SystemZAsmPrinter::emitStartOfAsmFile(Module &M) {
}
void SystemZAsmPrinter::emitPPA2(Module &M) {
+ ADASym = getObjFileLowering().getADASection()->getBeginSymbol();
+
OutStreamer->pushSection();
OutStreamer->switchSection(getObjFileLowering().getTextSection(),
GOFF::SK_PPA2);
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index cb101e472824f..19b517f82d658 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -31,6 +31,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
MCSymbol *CurrentFnPPA1Sym; // PPA1 Symbol.
MCSymbol *CurrentFnEPMarkerSym; // Entry Point Marker.
MCSymbol *PPA2Sym;
+ MCSymbol *ADASym;
SystemZTargetStreamer *getTargetStreamer() {
MCTargetStreamer *TS = OutStreamer->getTargetStreamer();
@@ -73,16 +74,17 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
/// @brief Add a function descriptor to the ADA.
/// @param MI Pointer to an ADA_ENTRY instruction.
- /// @return The displacement of the descriptor into the ADA.
- uint32_t insert(const MachineOperand MO);
+ /// @return The symbol and displacement of the descriptor into the ADA.
+ std::pair<const MCSymbol *, uint32_t> insert(const MachineOperand MO);
/// @brief Get the displacement into associated data area (ADA) for a name.
/// If no displacement is already associated with the name, assign one and
/// return it.
/// @param Sym The symbol for which the displacement should be returned.
/// @param SlotKind The ADA type.
- /// @return The displacement of the descriptor into the ADA.
- uint32_t insert(const MCSymbol *Sym, unsigned SlotKind);
+ /// @return The symbol and displacement of the descriptor into the ADA.
+ std::pair<const MCSymbol *, uint32_t> insert(const MCSymbol *Sym,
+ unsigned SlotKind);
/// Get the table of GOFF displacements. This is 'const' since it should
/// never be modified by anything except the APIs on this class.
@@ -101,13 +103,15 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
public:
SystemZAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer), ID), CurrentFnPPA1Sym(nullptr),
- CurrentFnEPMarkerSym(nullptr), PPA2Sym(nullptr),
+ CurrentFnEPMarkerSym(nullptr), PPA2Sym(nullptr), ADASym(nullptr),
ADATable(TM.getPointerSize(0)) {}
// Override AsmPrinter.
StringRef getPassName() const override { return "SystemZ Assembly Printer"; }
void emitInstruction(const MachineInstr *MI) override;
void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override;
+ void emitXXStructorList(const DataLayout &DL, const Constant *List,
+ bool IsCtor) override;
void emitEndOfAsmFile(Module &M) override;
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
const char *ExtraCode, raw_ostream &OS) override;
diff --git a/llvm/test/CodeGen/SystemZ/zos_sinit.ll b/llvm/test/CodeGen/SystemZ/zos_sinit.ll
new file mode 100644
index 0000000000000..036ec71466079
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/zos_sinit.ll
@@ -0,0 +1,36 @@
+; RUN: llc -emit-gnuas-syntax-on-zos=false < %s -mtriple=s390x-ibm-zos | \
+; RUN: FileCheck --check-prefixes=CHECK %s
+
+ at llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 22, ptr @cfuncctor, ptr null }]
+ at llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 22, ptr @cfuncdtor, ptr null }]
+
+; Check for presence of C_@@SQINIT:
+; CHECK: .xtor.22
+; CHECK: DC AD(cfuncctor)
+; CHECK: DC XL4'7FFF0017'
+; Check direct relocation and low bit on ctor.
+; CHECK: DC AD(QD(stdin#S)+XL8'0')
+; CHECK: DC XL8'0000000000000000'
+; CHECK: DC AD(cfuncdtor)
+; CHECK: DC XL4'7FFF0017'
+; CHECK: DC XL8'0000000000000000'
+; Check direct relocation and low bit on dtor.
+; CHECK: DC AD(QD(stdin#S)+XL8'16')
+
+; Check for function descriptors in ADA section:
+; CHECK: * Offset 0 function descriptor of cfuncctor
+; CHECK: DC RD(cfuncctor)
+; CHECK: DC VD(cfuncctor)
+; CHECK: * Offset 16 function descriptor of cfuncdtor
+; CHECK: DC RD(cfuncdtor)
+; CHECK: DC VD(cfuncdtor)
+
+define hidden void @cfuncctor() {
+entry:
+ ret void
+}
+
+define hidden void @cfuncdtor() {
+entry:
+ ret void
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/171476
More information about the llvm-branch-commits
mailing list