Skip to content

[GOFF] Add writing of text records #137235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: users/redstar/goffwriter-3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion llvm/include/llvm/MC/MCContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,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;
Expand Down
47 changes: 32 additions & 15 deletions llvm/include/llvm/MC/MCSectionGOFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's BSS, call it BSS.

Virtual seems a weird naming convention when the initial Mach-O MC code was added. New code doesn't need to endorse the weird naming.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not actually about BSS (those are named BSS - but they're not virtual). The "virtual" marker is for sections that represent those GOFF symbols that do not themselves contain text, but have nested GOFF sections which do. For example the section representing a SD GOFF section does not contain text directly, but it does contain ED sections; and sections representing a ED symbol with the merge attribute do not contain text directly, but contain PR sections.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly. The idea is to trigger the check in MCAssembler::writeSectionData() for those sections which are not allowed to contain text.

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,
Expand All @@ -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; }

Expand All @@ -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; }
Expand Down
78 changes: 78 additions & 0 deletions llvm/lib/MC/GOFFObjectWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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.
Expand Down
18 changes: 12 additions & 6 deletions llvm/lib/MC/MCContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,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());
Expand All @@ -688,28 +689,33 @@ 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;
}

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,
Expand Down
27 changes: 22 additions & 5 deletions llvm/test/CodeGen/SystemZ/zos-section-1.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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: 0000320 03 11 00 00 [[C_CODE64]] 00 00 00 00 00 00 00 00
; CHECK-NEXT: 0000330 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
30 changes: 25 additions & 5 deletions llvm/test/CodeGen/SystemZ/zos-section-2.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading