[llvm] 655d048 - [GOFF] Add writing of text records (#137235)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 26 10:50:43 PDT 2025
Author: Kai Nacke
Date: 2025-06-26T13:50:40-04:00
New Revision: 655d04859be6285e05e361044b7d11a5e29040b7
URL: https://github.com/llvm/llvm-project/commit/655d04859be6285e05e361044b7d11a5e29040b7
DIFF: https://github.com/llvm/llvm-project/commit/655d04859be6285e05e361044b7d11a5e29040b7.diff
LOG: [GOFF] Add writing of text records (#137235)
Sections which are not allowed to carry data are marked as virtual. Only
complication when writing out the text is that it must be written in
chunks of 32k-1 bytes, which is done by having a wrapper stream writing
those records.
Data of BSS sections is not written, since the contents is known to be
zero. Instead, the fill byte value is used.
Added:
Modified:
llvm/include/llvm/MC/MCContext.h
llvm/include/llvm/MC/MCSectionGOFF.h
llvm/lib/MC/GOFFObjectWriter.cpp
llvm/lib/MC/MCContext.cpp
llvm/test/CodeGen/SystemZ/zos-section-1.ll
llvm/test/CodeGen/SystemZ/zos-section-2.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index 50085c436c63c..d7b81af4a785a 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -359,7 +359,8 @@ class MCContext {
template <typename TAttr>
MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name,
- TAttr SDAttributes, MCSection *Parent);
+ TAttr SDAttributes, MCSection *Parent,
+ bool IsVirtual);
/// Map of currently defined macros.
StringMap<MCAsmMacro> MacroMap;
diff --git a/llvm/include/llvm/MC/MCSectionGOFF.h b/llvm/include/llvm/MC/MCSectionGOFF.h
index b8b8cf112a34d..b2ca74c3ba78a 100644
--- a/llvm/include/llvm/MC/MCSectionGOFF.h
+++ b/llvm/include/llvm/MC/MCSectionGOFF.h
@@ -39,6 +39,9 @@ class MCSectionGOFF final : public MCSection {
// The type of this section.
GOFF::ESDSymbolType SymbolType;
+ // This section is a BSS section.
+ unsigned IsBSS : 1;
+
// Indicates that the PR symbol needs to set the length of the section to a
// non-zero value. This is only a problem with the ADA PR - the binder will
// generate an error in this case.
@@ -50,26 +53,26 @@ class MCSectionGOFF final : public MCSection {
friend class MCContext;
friend class MCSymbolGOFF;
- MCSectionGOFF(StringRef Name, SectionKind K, GOFF::SDAttr SDAttributes,
- MCSectionGOFF *Parent)
- : MCSection(SV_GOFF, Name, K.isText(), /*IsVirtual=*/false, nullptr),
+ MCSectionGOFF(StringRef Name, SectionKind K, bool IsVirtual,
+ GOFF::SDAttr SDAttributes, MCSectionGOFF *Parent)
+ : MCSection(SV_GOFF, Name, K.isText(), IsVirtual, nullptr),
Parent(Parent), SDAttributes(SDAttributes),
- SymbolType(GOFF::ESD_ST_SectionDefinition), RequiresNonZeroLength(0),
- Emitted(0) {}
+ SymbolType(GOFF::ESD_ST_SectionDefinition), IsBSS(K.isBSS()),
+ RequiresNonZeroLength(0), Emitted(0) {}
- MCSectionGOFF(StringRef Name, SectionKind K, GOFF::EDAttr EDAttributes,
- MCSectionGOFF *Parent)
- : MCSection(SV_GOFF, Name, K.isText(), /*IsVirtual=*/false, nullptr),
+ MCSectionGOFF(StringRef Name, SectionKind K, bool IsVirtual,
+ GOFF::EDAttr EDAttributes, MCSectionGOFF *Parent)
+ : MCSection(SV_GOFF, Name, K.isText(), IsVirtual, nullptr),
Parent(Parent), EDAttributes(EDAttributes),
- SymbolType(GOFF::ESD_ST_ElementDefinition), RequiresNonZeroLength(0),
- Emitted(0) {}
+ SymbolType(GOFF::ESD_ST_ElementDefinition), IsBSS(K.isBSS()),
+ RequiresNonZeroLength(0), Emitted(0) {}
- MCSectionGOFF(StringRef Name, SectionKind K, GOFF::PRAttr PRAttributes,
- MCSectionGOFF *Parent)
- : MCSection(SV_GOFF, Name, K.isText(), /*IsVirtual=*/false, nullptr),
+ MCSectionGOFF(StringRef Name, SectionKind K, bool IsVirtual,
+ GOFF::PRAttr PRAttributes, MCSectionGOFF *Parent)
+ : MCSection(SV_GOFF, Name, K.isText(), IsVirtual, nullptr),
Parent(Parent), PRAttributes(PRAttributes),
- SymbolType(GOFF::ESD_ST_PartReference), RequiresNonZeroLength(0),
- Emitted(0) {}
+ SymbolType(GOFF::ESD_ST_PartReference), IsBSS(K.isBSS()),
+ RequiresNonZeroLength(0), Emitted(0) {}
public:
void printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
@@ -81,6 +84,9 @@ class MCSectionGOFF final : public MCSection {
// Return the parent section.
MCSectionGOFF *getParent() const { return Parent; }
+ // Returns true if this is a BSS section.
+ bool isBSS() const { return IsBSS; }
+
// Returns the type of this section.
GOFF::ESDSymbolType getSymbolType() const { return SymbolType; }
@@ -102,6 +108,17 @@ class MCSectionGOFF final : public MCSection {
return PRAttributes;
}
+ // Returns the text style for a section. Only defined for ED and PR sections.
+ GOFF::ESDTextStyle getTextStyle() const {
+ assert(isED() || isPR() || isVirtualSection() && "Expect ED or PR section");
+ if (isED())
+ return EDAttributes.TextStyle;
+ if (isPR())
+ return getParent()->getEDAttributes().TextStyle;
+ // Virtual sections have no data, so byte orientation is fine.
+ return GOFF::ESD_TS_ByteOriented;
+ }
+
bool requiresNonZeroLength() const { return RequiresNonZeroLength; }
void setName(StringRef SectionName) { Name = SectionName; }
diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp
index 1f3c131289b49..1871f5fe507e2 100644
--- a/llvm/lib/MC/GOFFObjectWriter.cpp
+++ b/llvm/lib/MC/GOFFObjectWriter.cpp
@@ -275,6 +275,7 @@ class GOFFWriter {
void writeHeader();
void writeSymbol(const GOFFSymbol &Symbol);
+ void writeText(const MCSectionGOFF *MC);
void writeEnd();
void defineSectionSymbols(const MCSectionGOFF &Section);
@@ -405,6 +406,80 @@ void GOFFWriter::writeSymbol(const GOFFSymbol &Symbol) {
OS.write(Name.data(), NameLength); // Name
}
+namespace {
+/// Adapter stream to write a text section.
+class TextStream : public raw_ostream {
+ /// The underlying GOFFOstream.
+ GOFFOstream &OS;
+
+ /// The buffer size is the maximum number of bytes in a TXT section.
+ static constexpr size_t BufferSize = GOFF::MaxDataLength;
+
+ /// Static allocated buffer for the stream, used by the raw_ostream class. The
+ /// buffer is sized to hold the payload of a logical TXT record.
+ char Buffer[BufferSize];
+
+ /// The offset for the next TXT record. This is equal to the number of bytes
+ /// written.
+ size_t Offset;
+
+ /// The Esdid of the GOFF section.
+ const uint32_t EsdId;
+
+ /// The record style.
+ const GOFF::ESDTextStyle RecordStyle;
+
+ /// See raw_ostream::write_impl.
+ void write_impl(const char *Ptr, size_t Size) override;
+
+ uint64_t current_pos() const override { return Offset; }
+
+public:
+ explicit TextStream(GOFFOstream &OS, uint32_t EsdId,
+ GOFF::ESDTextStyle RecordStyle)
+ : OS(OS), Offset(0), EsdId(EsdId), RecordStyle(RecordStyle) {
+ SetBuffer(Buffer, sizeof(Buffer));
+ }
+
+ ~TextStream() { flush(); }
+};
+} // namespace
+
+void TextStream::write_impl(const char *Ptr, size_t Size) {
+ size_t WrittenLength = 0;
+
+ // We only have signed 32bits of offset.
+ if (Offset + Size > std::numeric_limits<int32_t>::max())
+ report_fatal_error("TXT section too large");
+
+ while (WrittenLength < Size) {
+ size_t ToWriteLength =
+ std::min(Size - WrittenLength, size_t(GOFF::MaxDataLength));
+
+ OS.newRecord(GOFF::RT_TXT);
+ OS.writebe<uint8_t>(GOFF::Flags(4, 4, RecordStyle)); // Text Record Style
+ OS.writebe<uint32_t>(EsdId); // Element ESDID
+ OS.writebe<uint32_t>(0); // Reserved
+ OS.writebe<uint32_t>(static_cast<uint32_t>(Offset)); // Offset
+ OS.writebe<uint32_t>(0); // Text Field True Length
+ OS.writebe<uint16_t>(0); // Text Encoding
+ OS.writebe<uint16_t>(ToWriteLength); // Data Length
+ OS.write(Ptr + WrittenLength, ToWriteLength); // Data
+
+ WrittenLength += ToWriteLength;
+ Offset += ToWriteLength;
+ }
+}
+
+void GOFFWriter::writeText(const MCSectionGOFF *Section) {
+ // A BSS section contains only zeros, no need to write this.
+ if (Section->isBSS())
+ return;
+
+ TextStream S(OS, Section->getOrdinal(), Section->getTextStyle());
+ Asm.writeSectionData(S, Section);
+}
+
void GOFFWriter::writeEnd() {
uint8_t F = GOFF::END_EPR_None;
uint8_t AMODE = 0;
@@ -428,6 +503,9 @@ uint64_t GOFFWriter::writeObject() {
defineSymbols();
+ for (const MCSection &Section : Asm)
+ writeText(static_cast<const MCSectionGOFF *>(&Section));
+
writeEnd();
// Make sure all records are written.
diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index f3bb5aa88e8fb..3f2f9a756d33b 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/lib/MC/MCContext.cpp
@@ -723,7 +723,8 @@ MCContext::getELFUniqueIDForEntsize(StringRef SectionName, unsigned Flags,
template <typename TAttr>
MCSectionGOFF *MCContext::getGOFFSection(SectionKind Kind, StringRef Name,
- TAttr Attributes, MCSection *Parent) {
+ TAttr Attributes, MCSection *Parent,
+ bool IsVirtual) {
std::string UniqueName(Name);
if (Parent) {
UniqueName.append("/").append(Parent->getName());
@@ -737,8 +738,9 @@ MCSectionGOFF *MCContext::getGOFFSection(SectionKind Kind, StringRef Name,
return Iter->second;
StringRef CachedName = StringRef(Iter->first.c_str(), Name.size());
- MCSectionGOFF *GOFFSection = new (GOFFAllocator.Allocate()) MCSectionGOFF(
- CachedName, Kind, Attributes, static_cast<MCSectionGOFF *>(Parent));
+ MCSectionGOFF *GOFFSection = new (GOFFAllocator.Allocate())
+ MCSectionGOFF(CachedName, Kind, IsVirtual, Attributes,
+ static_cast<MCSectionGOFF *>(Parent));
Iter->second = GOFFSection;
allocInitialFragment(*GOFFSection);
return GOFFSection;
@@ -746,19 +748,23 @@ MCSectionGOFF *MCContext::getGOFFSection(SectionKind Kind, StringRef Name,
MCSectionGOFF *MCContext::getGOFFSection(SectionKind Kind, StringRef Name,
GOFF::SDAttr SDAttributes) {
- return getGOFFSection<GOFF::SDAttr>(Kind, Name, SDAttributes, nullptr);
+ return getGOFFSection<GOFF::SDAttr>(Kind, Name, SDAttributes, nullptr,
+ /*IsVirtual=*/true);
}
MCSectionGOFF *MCContext::getGOFFSection(SectionKind Kind, StringRef Name,
GOFF::EDAttr EDAttributes,
MCSection *Parent) {
- return getGOFFSection<GOFF::EDAttr>(Kind, Name, EDAttributes, Parent);
+ return getGOFFSection<GOFF::EDAttr>(
+ Kind, Name, EDAttributes, Parent,
+ /*IsVirtual=*/EDAttributes.BindAlgorithm == GOFF::ESD_BA_Merge);
}
MCSectionGOFF *MCContext::getGOFFSection(SectionKind Kind, StringRef Name,
GOFF::PRAttr PRAttributes,
MCSection *Parent) {
- return getGOFFSection<GOFF::PRAttr>(Kind, Name, PRAttributes, Parent);
+ return getGOFFSection<GOFF::PRAttr>(Kind, Name, PRAttributes, Parent,
+ /*IsVirtual=*/false);
}
MCSectionCOFF *MCContext::getCOFFSection(StringRef Section,
diff --git a/llvm/test/CodeGen/SystemZ/zos-section-1.ll b/llvm/test/CodeGen/SystemZ/zos-section-1.ll
index ea9bc4ce95174..b98584df54d5a 100644
--- a/llvm/test/CodeGen/SystemZ/zos-section-1.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-section-1.ll
@@ -104,9 +104,26 @@ entry:
; CHECK-NEXT: 000300 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02
; CHECK-NEXT: 000310 00 01 20 00 00 00 00 06 a3 85 a2 a3 7b c3 00 00
+; Text record for the code section C_CODE64.
+; The regular expression matches the lower byte of the length.
+; CHECK-NEXT: 000320 03 11 00 00 [[C_CODE64]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000330 00 00 00 00 00 00 00 {{..}} 00 c3 00 c5 00 c5 00 f1
+
+; Text record for the section .&ppa2.
+; CHECK: 0003c0 03 10 00 00 [[PPA2]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0003d0 00 00 00 00 00 00 00 {{..}} {{.*}}
+
+; Text record for the ADA section test#S.
+; CHECK: 000410 03 10 00 00 [[TESTS]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000420 00 00 00 00 00 00 00 {{..}} {{.*}}
+
+; Text record for the section B_IDRL.
+; CHECK: 000460 03 10 00 01 [[BIDRL]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000470 00 00 00 00 00 00 00 {{..}} {{.*}}
+
; End record.
-; CHECK-NEXT: 000320 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000340 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000350 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000360 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0004b0 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0004c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0004d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0004e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0004f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
diff --git a/llvm/test/CodeGen/SystemZ/zos-section-2.ll b/llvm/test/CodeGen/SystemZ/zos-section-2.ll
index 472517acc4a45..0f608c1206b96 100644
--- a/llvm/test/CodeGen/SystemZ/zos-section-2.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-section-2.ll
@@ -147,9 +147,29 @@ source_filename = "test.ll"
; CHECK-NEXT: 0004e0 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02
; CHECK-NEXT: 0004f0 00 01 20 00 00 00 00 06 a3 85 a2 a3 7b c3 00 00
+; Text record for the code section C_CODE64.
+; The regular expression matches the lower byte of the length.
+; CHECK-NEXT: 000500 03 10 00 00 [[C_CODE64]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000510 00 00 00 00 00 00 00 {{..}} {{.*}}
+
+; Text record for the section .&ppa2.
+; CHECK: 000550 03 10 00 00 [[PPA2]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000560 00 00 00 00 00 00 00 {{..}} {{.*}}
+
+; Text record for the section data.
+; Length is 4, and the content is 0x2a = 42.
+; CHECK: 0005a0 03 10 00 00 [[DATA_PR]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0005b0 00 00 00 00 00 00 00 04 00 00 00 2a 00 00 00 00
+
+; There is no text record for section bss!
+
+; Text record for the section B_IDRL.
+; CHECK: 0005f0 03 10 00 01 [[BIDRL]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000600 00 00 00 00 00 00 00 {{..}} {{.*}}
+
; End record.
-; CHECK-NEXT: 000500 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000510 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000520 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000530 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000540 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000640 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000650 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000660 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000670 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000680 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
More information about the llvm-commits
mailing list