Skip to content

[GOFF] Add writing of section symbols #133799

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 35 commits into
base: users/redstar/goffwriter-2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
77c230f
[GOFF] Add writing of section symbols
redstar Mar 24, 2025
bb71a07
Update llvm/include/llvm/MC/MCGOFFSymbolMapper.h
redstar Apr 2, 2025
a0a2a1f
Update llvm/include/llvm/MC/MCGOFFSymbolMapper.h
redstar Apr 2, 2025
18cd9eb
Update llvm/lib/MC/GOFFObjectWriter.cpp
redstar Apr 2, 2025
f2be856
More updates
redstar Apr 2, 2025
3cf7324
Remove the class GOFFSymbolMapper
redstar Apr 2, 2025
686b628
Update formatting
redstar Apr 2, 2025
c7fcda9
More updates
redstar Apr 3, 2025
1ca5fdc
Fix failing tests
redstar Apr 4, 2025
682f07b
Rework based on reviewer comment.
redstar Apr 5, 2025
5d522fd
More work on reviewer comments
redstar Apr 7, 2025
74e804c
Emit CSECT/CATTR
redstar Apr 7, 2025
c541729
Fix key for hashmap and introduce union
redstar Apr 8, 2025
469206d
Use getOrdinal/getIndex as the GOFF symbol id.
redstar Apr 8, 2025
f859b78
Remove initSections()
redstar Apr 8, 2025
7be8fa3
Remove RootSDSection
redstar Apr 8, 2025
f358e40
Fix formatting and assertions
redstar Apr 9, 2025
83440e1
Update the test case to cover all records in the file.
redstar Apr 9, 2025
b6b261a
Reuse NameSpace from ED in PR/LD
redstar Apr 11, 2025
01549d4
Also set FillByteValue.
redstar Apr 11, 2025
4d7e8c5
- Amode only for LD
redstar Apr 14, 2025
1926203
Emit XATTR
redstar Apr 14, 2025
adef64a
Remove comma and add part name.
redstar Apr 15, 2025
a4b425f
Fix test case due to removed comma
redstar Apr 15, 2025
0b54967
Remove DuplicateSymbolSeverity since it is not required.
redstar Apr 15, 2025
7576e13
Change code as recommended by MaskRay
redstar Apr 15, 2025
7803d02
Move .ll test cases
redstar Apr 15, 2025
5810c44
Add another test case, and remove -o - in the run line
redstar Apr 15, 2025
ba1223a
Remove Executable from the ED element
redstar Apr 23, 2025
2f6babe
Remove unused header file
redstar Apr 24, 2025
005bd75
Remove ReadOnly attribute for PR elements
redstar Apr 29, 2025
7ba4c75
Make alignment of PR always the same as ED
redstar Apr 29, 2025
9f0aa12
Fix test cases
redstar Apr 29, 2025
4883fc3
Lift fill byte value to higher layer.
redstar Apr 29, 2025
1e4c700
Fix formatting.
redstar Apr 30, 2025
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
85 changes: 85 additions & 0 deletions llvm/include/llvm/BinaryFormat/GOFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,91 @@ enum SubsectionKind : uint8_t {
SK_PPA1 = 2,
SK_PPA2 = 4,
};

// The standard System/390 convention is to name the high-order (leftmost) bit
// in a byte as bit zero. The Flags type helps to set bits in byte according
// to this numeration order.
class Flags {
uint8_t Val = 0;

constexpr static uint8_t bits(uint8_t BitIndex, uint8_t Length, uint8_t Value,
uint8_t OldValue) {
uint8_t Pos = 8 - BitIndex - Length;
uint8_t Mask = ((1 << Length) - 1) << Pos;
Value = Value << Pos;
return (OldValue & ~Mask) | Value;
}

public:
constexpr Flags() = default;
constexpr Flags(uint8_t BitIndex, uint8_t Length, uint8_t Value)
: Val(bits(BitIndex, Length, Value, 0)) {}

template <typename T>
constexpr void set(uint8_t BitIndex, uint8_t Length, T NewValue) {
Val = bits(BitIndex, Length, static_cast<uint8_t>(NewValue), Val);
}

template <typename T>
constexpr T get(uint8_t BitIndex, uint8_t Length) const {
return static_cast<T>((Val >> (8 - BitIndex - Length)) &
((1 << Length) - 1));
}

constexpr operator uint8_t() const { return Val; }
};

// Structure for the flag field of a symbol. See
// https://www.ibm.com/docs/en/zos/3.1.0?topic=formats-external-symbol-definition-record
// at offset 41 for the definition.
struct SymbolFlags {
Flags SymFlags;

#define GOFF_SYMBOL_FLAG(NAME, TYPE, BITINDEX, LENGTH) \
void set##NAME(TYPE Val) { SymFlags.set<TYPE>(BITINDEX, LENGTH, Val); } \
TYPE get##NAME() const { return SymFlags.get<TYPE>(BITINDEX, LENGTH); }

GOFF_SYMBOL_FLAG(FillBytePresence, bool, 0, 1)
GOFF_SYMBOL_FLAG(Mangled, bool, 1, 1)
GOFF_SYMBOL_FLAG(Renameable, bool, 2, 1)
GOFF_SYMBOL_FLAG(RemovableClass, bool, 3, 1)
GOFF_SYMBOL_FLAG(ReservedQwords, ESDReserveQwords, 5, 3)
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like I once knew the answer to this question but I have since forgotten...

What's up with this field? The documentation linked a few lines above say that field is reserved - does the documentation need an update, or can this be removed?

Copy link
Member Author

Choose a reason for hiding this comment

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

For ED- and PR-type records, this field specifies the amount of space (in multiples of 16-byte quadwords) that the Binder will reserve at the origin of an element.
It's required, and the documentation needs an update.


#undef GOFF_SYMBOL_FLAG

constexpr operator uint8_t() const { return static_cast<uint8_t>(SymFlags); }
};

// Structure for the behavioral attributes. See
// https://www.ibm.com/docs/en/zos/3.1.0?topic=record-external-symbol-definition-behavioral-attributes
// for the definition.
struct BehavioralAttributes {
Flags Attr[10];

#define GOFF_BEHAVIORAL_ATTRIBUTE(NAME, TYPE, ATTRIDX, BITINDEX, LENGTH) \
void set##NAME(TYPE Val) { Attr[ATTRIDX].set<TYPE>(BITINDEX, LENGTH, Val); } \
TYPE get##NAME() const { return Attr[ATTRIDX].get<TYPE>(BITINDEX, LENGTH); }

GOFF_BEHAVIORAL_ATTRIBUTE(Amode, GOFF::ESDAmode, 0, 0, 8)
GOFF_BEHAVIORAL_ATTRIBUTE(Rmode, GOFF::ESDRmode, 1, 0, 8)
GOFF_BEHAVIORAL_ATTRIBUTE(TextStyle, GOFF::ESDTextStyle, 2, 0, 4)
GOFF_BEHAVIORAL_ATTRIBUTE(BindingAlgorithm, GOFF::ESDBindingAlgorithm, 2, 4,
4)
GOFF_BEHAVIORAL_ATTRIBUTE(TaskingBehavior, GOFF::ESDTaskingBehavior, 3, 0, 3)
GOFF_BEHAVIORAL_ATTRIBUTE(ReadOnly, bool, 3, 4, 1)
GOFF_BEHAVIORAL_ATTRIBUTE(Executable, GOFF::ESDExecutable, 3, 5, 3)
GOFF_BEHAVIORAL_ATTRIBUTE(DuplicateSymbolSeverity,
GOFF::ESDDuplicateSymbolSeverity, 4, 2, 2)
GOFF_BEHAVIORAL_ATTRIBUTE(BindingStrength, GOFF::ESDBindingStrength, 4, 4, 4)
GOFF_BEHAVIORAL_ATTRIBUTE(LoadingBehavior, GOFF::ESDLoadingBehavior, 5, 0, 2)
GOFF_BEHAVIORAL_ATTRIBUTE(COMMON, bool, 5, 2, 1)
GOFF_BEHAVIORAL_ATTRIBUTE(IndirectReference, bool, 5, 3, 1)
GOFF_BEHAVIORAL_ATTRIBUTE(BindingScope, GOFF::ESDBindingScope, 5, 4, 4)
GOFF_BEHAVIORAL_ATTRIBUTE(LinkageType, GOFF::ESDLinkageType, 6, 2, 1)
GOFF_BEHAVIORAL_ATTRIBUTE(Alignment, GOFF::ESDAlignment, 6, 3, 5)

#undef GOFF_BEHAVIORAL_ATTRIBUTE
};
} // end namespace GOFF

} // end namespace llvm
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,10 +316,15 @@ class TargetLoweringObjectFileXCOFF : public TargetLoweringObjectFile {
};

class TargetLoweringObjectFileGOFF : public TargetLoweringObjectFile {
std::string DefaultRootSDName;
std::string DefaultADAPRName;

public:
TargetLoweringObjectFileGOFF();
~TargetLoweringObjectFileGOFF() override = default;

void getModuleMetadata(Module &M) override;

MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const override;
MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind,
Expand Down
15 changes: 12 additions & 3 deletions llvm/include/llvm/MC/MCContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
#include "llvm/BinaryFormat/XCOFF.h"
#include "llvm/MC/MCAsmMacro.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCGOFFAttributes.h"
#include "llvm/MC/MCPseudoProbe.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSectionGOFF.h"
#include "llvm/MC/MCSymbolTableEntry.h"
#include "llvm/MC/SectionKind.h"
#include "llvm/Support/Allocator.h"
Expand Down Expand Up @@ -54,7 +56,6 @@ class MCSection;
class MCSectionCOFF;
class MCSectionDXContainer;
class MCSectionELF;
class MCSectionGOFF;
class MCSectionMachO;
class MCSectionSPIRV;
class MCSectionWasm;
Expand Down Expand Up @@ -363,6 +364,10 @@ class MCContext {
MCSymbolXCOFF *createXCOFFSymbolImpl(const MCSymbolTableEntry *Name,
bool IsTemporary);

template <typename TAttr>
MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name,
TAttr SDAttributes, MCSection *Parent);

/// Map of currently defined macros.
StringMap<MCAsmMacro> MacroMap;

Expand Down Expand Up @@ -599,8 +604,12 @@ class MCContext {
unsigned Flags,
unsigned EntrySize);

MCSectionGOFF *getGOFFSection(StringRef Section, SectionKind Kind,
MCSection *Parent, uint32_t Subsection = 0);
MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name,
GOFF::SDAttr SDAttributes);
MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name,
GOFF::EDAttr EDAttributes, MCSection *Parent);
MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name,
GOFF::PRAttr PRAttributes, MCSection *Parent);

MCSectionCOFF *getCOFFSection(StringRef Section, unsigned Characteristics,
StringRef COMDATSymName, int Selection,
Expand Down
106 changes: 106 additions & 0 deletions llvm/include/llvm/MC/MCGOFFAttributes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//===- MCGOFFAttributes.h - Attributes of GOFF symbols --------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Defines the various attribute collections defining GOFF symbols.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_MC_MCGOFFATTRIBUTES_H
#define LLVM_MC_MCGOFFATTRIBUTES_H

#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/GOFF.h"
#include <cstdint>

namespace llvm {
namespace GOFF {
// An "External Symbol Definition" in the GOFF file has a type, and depending on
// the type a different subset of the fields is used.
//
// Unlike other formats, a 2 dimensional structure is used to define the
// location of data. For example, the equivalent of the ELF .text section is
// made up of a Section Definition (SD) and a class (Element Definition; ED).
// The name of the SD symbol depends on the application, while the class has the
// predefined name C_CODE/C_CODE64 in AMODE31 and AMODE64 respectively.
//
// Data can be placed into this structure in 2 ways. First, the data (in a text
// record) can be associated with an ED symbol. To refer to data, a Label
// Definition (LD) is used to give an offset into the data a name. When binding,
// the whole data is pulled into the resulting executable, and the addresses
// given by the LD symbols are resolved.
//
// The alternative is to use a Part Definition (PR). In this case, the data (in
// a text record) is associated with the part. When binding, only the data of
// referenced PRs is pulled into the resulting binary.
//
// Both approaches are used, which means that the equivalent of a section in ELF
// results in 3 GOFF symbols, either SD/ED/LD or SD/ED/PR. Moreover, certain
// sections are fine with just defining SD/ED symbols. The SymbolMapper takes
// care of all those details.

// Attributes for SD symbols.
struct SDAttr {
GOFF::ESDTaskingBehavior TaskingBehavior = GOFF::ESD_TA_Unspecified;
GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified;
};

// Attributes for ED symbols.
struct EDAttr {
bool IsReadOnly = false;
GOFF::ESDRmode Rmode;
GOFF::ESDNameSpaceId NameSpace = GOFF::ESD_NS_NormalName;
GOFF::ESDTextStyle TextStyle = GOFF::ESD_TS_ByteOriented;
GOFF::ESDBindingAlgorithm BindAlgorithm = GOFF::ESD_BA_Concatenate;
GOFF::ESDLoadingBehavior LoadBehavior = GOFF::ESD_LB_Initial;
GOFF::ESDReserveQwords ReservedQwords = GOFF::ESD_RQ_0;
GOFF::ESDAlignment Alignment = GOFF::ESD_ALIGN_Doubleword;
uint8_t FillByteValue = 0;
};

// Attributes for LD symbols.
struct LDAttr {
bool IsRenamable = false;
GOFF::ESDExecutable Executable = GOFF::ESD_EXE_Unspecified;
GOFF::ESDBindingStrength BindingStrength = GOFF::ESD_BST_Strong;
Copy link
Member

Choose a reason for hiding this comment

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

For LD (as opposed to ER), it seems "strong" is the only allowed value here. Again, if this is true, it doesn't make much sense to specify it.

Copy link
Member Author

@redstar redstar Apr 15, 2025

Choose a reason for hiding this comment

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

This is actually needed for C++ inline functions etc. which can end up in several object files. Also for weak definitions, e.g.:

// a.c
#include <stdio.h>

__attribute__((weak)) void fun() {
  printf("Weak fun\n");
}

void feature() {
  fun();
}

and

// b.c
#include <stdio.h>

extern void feature();

void fun() {
  printf("Other fun\n");
}

int main(int argc, char *argv[]) {
  feature();
  return 0;
}

(example taken from a blog by @MaskRay)

Another case were the documentation needs an update.

Copy link
Member

Choose a reason for hiding this comment

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

I see. This is not currently reflected in the HLASM output, however. How would one do this?

Copy link
Member Author

Choose a reason for hiding this comment

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

I need to ask for this. I see only WXTRN for weak externals in the HLASM documentation.

GOFF::ESDLinkageType Linkage = GOFF::ESD_LT_XPLink;
GOFF::ESDAmode Amode;
GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified;
};

// Attributes for PR symbols.
struct PRAttr {
bool IsRenamable = false;
GOFF::ESDExecutable Executable = GOFF::ESD_EXE_Unspecified;
GOFF::ESDLinkageType Linkage = GOFF::ESD_LT_XPLink;
GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified;
uint32_t SortKey = 0;
};

// Class names and other values depending on AMODE64 or AMODE31, and other
// environment properties. For now, only the 64 bit XPLINK case is defined.

// GOFF classes.
constexpr StringLiteral CLASS_CODE = "C_CODE64";
constexpr StringLiteral CLASS_WSA = "C_WSA64";
constexpr StringLiteral CLASS_DATA = "C_DATA64";
constexpr StringLiteral CLASS_PPA2 = "C_@@QPPA2";

// Addres and residency mode.
constexpr GOFF::ESDAmode AMODE = GOFF::ESD_AMODE_64;
constexpr GOFF::ESDRmode RMODE = GOFF::ESD_RMODE_64;

// Linkage.
constexpr GOFF::ESDLinkageType LINKAGE = GOFF::ESD_LT_XPLink;

// Loadding behavior.
constexpr GOFF::ESDLoadingBehavior LOADBEHAVIOR = GOFF::ESD_LB_Initial;

} // namespace GOFF
} // namespace llvm

#endif
3 changes: 3 additions & 0 deletions llvm/include/llvm/MC/MCGOFFStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace llvm {
class GOFFObjectWriter;

class MCGOFFStreamer : public MCObjectStreamer {

public:
MCGOFFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
std::unique_ptr<MCObjectWriter> OW,
Expand All @@ -25,6 +26,8 @@ class MCGOFFStreamer : public MCObjectStreamer {

~MCGOFFStreamer() override;

void changeSection(MCSection *Section, uint32_t Subsection = 0) override;

GOFFObjectWriter &getWriter();

bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
Expand Down
4 changes: 0 additions & 4 deletions llvm/include/llvm/MC/MCObjectFileInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,6 @@ class MCObjectFileInfo {
MCSection *GLJMPSection = nullptr;

// GOFF specific sections.
MCSection *PPA1Section = nullptr;
MCSection *PPA2Section = nullptr;
MCSection *PPA2ListSection = nullptr;
MCSection *ADASection = nullptr;
MCSection *IDRLSection = nullptr;
Expand Down Expand Up @@ -438,8 +436,6 @@ class MCObjectFileInfo {
MCSection *getGLJMPSection() const { return GLJMPSection; }

// GOFF specific sections.
MCSection *getPPA1Section() const { return PPA1Section; }
MCSection *getPPA2Section() const { return PPA2Section; }
MCSection *getPPA2ListSection() const { return PPA2ListSection; }
MCSection *getADASection() const { return ADASection; }
MCSection *getIDRLSection() const { return IDRLSection; }
Expand Down
Loading
Loading