Skip to content

Commit 33872f1

Browse files
authored
[GOFF] Add writing of section symbols (#133799)
Unlike other formats, the GOFF object file format uses a 2 dimensional structure 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. SD, ED, and PR elements are modeled by nested MCSectionGOFF instances, while LD elements are associated with MCSymbolGOFF instances. At the binary level, a record called "External Symbol Definition" (ESD) is used. The ESD has a type (SD, ED, PR, LD), and depending on the type a different subset of the fields is used.
1 parent 6bdfeca commit 33872f1

25 files changed

+1097
-97
lines changed

llvm/include/llvm/BinaryFormat/GOFF.h

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,91 @@ enum SubsectionKind : uint8_t {
169169
SK_PPA1 = 2,
170170
SK_PPA2 = 4,
171171
};
172+
173+
// The standard System/390 convention is to name the high-order (leftmost) bit
174+
// in a byte as bit zero. The Flags type helps to set bits in byte according
175+
// to this numeration order.
176+
class Flags {
177+
uint8_t Val = 0;
178+
179+
constexpr static uint8_t bits(uint8_t BitIndex, uint8_t Length, uint8_t Value,
180+
uint8_t OldValue) {
181+
uint8_t Pos = 8 - BitIndex - Length;
182+
uint8_t Mask = ((1 << Length) - 1) << Pos;
183+
Value = Value << Pos;
184+
return (OldValue & ~Mask) | Value;
185+
}
186+
187+
public:
188+
constexpr Flags() = default;
189+
constexpr Flags(uint8_t BitIndex, uint8_t Length, uint8_t Value)
190+
: Val(bits(BitIndex, Length, Value, 0)) {}
191+
192+
template <typename T>
193+
constexpr void set(uint8_t BitIndex, uint8_t Length, T NewValue) {
194+
Val = bits(BitIndex, Length, static_cast<uint8_t>(NewValue), Val);
195+
}
196+
197+
template <typename T>
198+
constexpr T get(uint8_t BitIndex, uint8_t Length) const {
199+
return static_cast<T>((Val >> (8 - BitIndex - Length)) &
200+
((1 << Length) - 1));
201+
}
202+
203+
constexpr operator uint8_t() const { return Val; }
204+
};
205+
206+
// Structure for the flag field of a symbol. See
207+
// https://www.ibm.com/docs/en/zos/3.1.0?topic=formats-external-symbol-definition-record
208+
// at offset 41 for the definition.
209+
struct SymbolFlags {
210+
Flags SymFlags;
211+
212+
#define GOFF_SYMBOL_FLAG(NAME, TYPE, BITINDEX, LENGTH) \
213+
void set##NAME(TYPE Val) { SymFlags.set<TYPE>(BITINDEX, LENGTH, Val); } \
214+
TYPE get##NAME() const { return SymFlags.get<TYPE>(BITINDEX, LENGTH); }
215+
216+
GOFF_SYMBOL_FLAG(FillBytePresence, bool, 0, 1)
217+
GOFF_SYMBOL_FLAG(Mangled, bool, 1, 1)
218+
GOFF_SYMBOL_FLAG(Renameable, bool, 2, 1)
219+
GOFF_SYMBOL_FLAG(RemovableClass, bool, 3, 1)
220+
GOFF_SYMBOL_FLAG(ReservedQwords, ESDReserveQwords, 5, 3)
221+
222+
#undef GOFF_SYMBOL_FLAG
223+
224+
constexpr operator uint8_t() const { return static_cast<uint8_t>(SymFlags); }
225+
};
226+
227+
// Structure for the behavioral attributes. See
228+
// https://www.ibm.com/docs/en/zos/3.1.0?topic=record-external-symbol-definition-behavioral-attributes
229+
// for the definition.
230+
struct BehavioralAttributes {
231+
Flags Attr[10];
232+
233+
#define GOFF_BEHAVIORAL_ATTRIBUTE(NAME, TYPE, ATTRIDX, BITINDEX, LENGTH) \
234+
void set##NAME(TYPE Val) { Attr[ATTRIDX].set<TYPE>(BITINDEX, LENGTH, Val); } \
235+
TYPE get##NAME() const { return Attr[ATTRIDX].get<TYPE>(BITINDEX, LENGTH); }
236+
237+
GOFF_BEHAVIORAL_ATTRIBUTE(Amode, GOFF::ESDAmode, 0, 0, 8)
238+
GOFF_BEHAVIORAL_ATTRIBUTE(Rmode, GOFF::ESDRmode, 1, 0, 8)
239+
GOFF_BEHAVIORAL_ATTRIBUTE(TextStyle, GOFF::ESDTextStyle, 2, 0, 4)
240+
GOFF_BEHAVIORAL_ATTRIBUTE(BindingAlgorithm, GOFF::ESDBindingAlgorithm, 2, 4,
241+
4)
242+
GOFF_BEHAVIORAL_ATTRIBUTE(TaskingBehavior, GOFF::ESDTaskingBehavior, 3, 0, 3)
243+
GOFF_BEHAVIORAL_ATTRIBUTE(ReadOnly, bool, 3, 4, 1)
244+
GOFF_BEHAVIORAL_ATTRIBUTE(Executable, GOFF::ESDExecutable, 3, 5, 3)
245+
GOFF_BEHAVIORAL_ATTRIBUTE(DuplicateSymbolSeverity,
246+
GOFF::ESDDuplicateSymbolSeverity, 4, 2, 2)
247+
GOFF_BEHAVIORAL_ATTRIBUTE(BindingStrength, GOFF::ESDBindingStrength, 4, 4, 4)
248+
GOFF_BEHAVIORAL_ATTRIBUTE(LoadingBehavior, GOFF::ESDLoadingBehavior, 5, 0, 2)
249+
GOFF_BEHAVIORAL_ATTRIBUTE(COMMON, bool, 5, 2, 1)
250+
GOFF_BEHAVIORAL_ATTRIBUTE(IndirectReference, bool, 5, 3, 1)
251+
GOFF_BEHAVIORAL_ATTRIBUTE(BindingScope, GOFF::ESDBindingScope, 5, 4, 4)
252+
GOFF_BEHAVIORAL_ATTRIBUTE(LinkageType, GOFF::ESDLinkageType, 6, 2, 1)
253+
GOFF_BEHAVIORAL_ATTRIBUTE(Alignment, GOFF::ESDAlignment, 6, 3, 5)
254+
255+
#undef GOFF_BEHAVIORAL_ATTRIBUTE
256+
};
172257
} // end namespace GOFF
173258

174259
} // end namespace llvm

llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,10 +316,15 @@ class TargetLoweringObjectFileXCOFF : public TargetLoweringObjectFile {
316316
};
317317

318318
class TargetLoweringObjectFileGOFF : public TargetLoweringObjectFile {
319+
std::string DefaultRootSDName;
320+
std::string DefaultADAPRName;
321+
319322
public:
320323
TargetLoweringObjectFileGOFF();
321324
~TargetLoweringObjectFileGOFF() override = default;
322325

326+
void getModuleMetadata(Module &M) override;
327+
323328
MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
324329
const TargetMachine &TM) const override;
325330
MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind,

llvm/include/llvm/MC/MCContext.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
#include "llvm/BinaryFormat/XCOFF.h"
2020
#include "llvm/MC/MCAsmMacro.h"
2121
#include "llvm/MC/MCDwarf.h"
22+
#include "llvm/MC/MCGOFFAttributes.h"
2223
#include "llvm/MC/MCPseudoProbe.h"
2324
#include "llvm/MC/MCSection.h"
25+
#include "llvm/MC/MCSectionGOFF.h"
2426
#include "llvm/MC/MCSymbolTableEntry.h"
2527
#include "llvm/MC/SectionKind.h"
2628
#include "llvm/Support/Allocator.h"
@@ -54,7 +56,6 @@ class MCSection;
5456
class MCSectionCOFF;
5557
class MCSectionDXContainer;
5658
class MCSectionELF;
57-
class MCSectionGOFF;
5859
class MCSectionMachO;
5960
class MCSectionSPIRV;
6061
class MCSectionWasm;
@@ -356,6 +357,10 @@ class MCContext {
356357
MCSymbolXCOFF *createXCOFFSymbolImpl(const MCSymbolTableEntry *Name,
357358
bool IsTemporary);
358359

360+
template <typename TAttr>
361+
MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name,
362+
TAttr SDAttributes, MCSection *Parent);
363+
359364
/// Map of currently defined macros.
360365
StringMap<MCAsmMacro> MacroMap;
361366

@@ -606,9 +611,12 @@ class MCContext {
606611
getELFUniqueIDForEntsize(StringRef SectionName, unsigned Flags,
607612
unsigned EntrySize);
608613

609-
LLVM_ABI MCSectionGOFF *getGOFFSection(StringRef Section, SectionKind Kind,
610-
MCSection *Parent,
611-
uint32_t Subsection = 0);
614+
MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name,
615+
GOFF::SDAttr SDAttributes);
616+
MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name,
617+
GOFF::EDAttr EDAttributes, MCSection *Parent);
618+
MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name,
619+
GOFF::PRAttr PRAttributes, MCSection *Parent);
612620

613621
LLVM_ABI MCSectionCOFF *
614622
getCOFFSection(StringRef Section, unsigned Characteristics,
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//===- MCGOFFAttributes.h - Attributes of GOFF symbols --------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Defines the various attribute collections defining GOFF symbols.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_MC_MCGOFFATTRIBUTES_H
14+
#define LLVM_MC_MCGOFFATTRIBUTES_H
15+
16+
#include "llvm/ADT/StringRef.h"
17+
#include "llvm/BinaryFormat/GOFF.h"
18+
#include <cstdint>
19+
20+
namespace llvm {
21+
namespace GOFF {
22+
// An "External Symbol Definition" in the GOFF file has a type, and depending on
23+
// the type a different subset of the fields is used.
24+
//
25+
// Unlike other formats, a 2 dimensional structure is used to define the
26+
// location of data. For example, the equivalent of the ELF .text section is
27+
// made up of a Section Definition (SD) and a class (Element Definition; ED).
28+
// The name of the SD symbol depends on the application, while the class has the
29+
// predefined name C_CODE/C_CODE64 in AMODE31 and AMODE64 respectively.
30+
//
31+
// Data can be placed into this structure in 2 ways. First, the data (in a text
32+
// record) can be associated with an ED symbol. To refer to data, a Label
33+
// Definition (LD) is used to give an offset into the data a name. When binding,
34+
// the whole data is pulled into the resulting executable, and the addresses
35+
// given by the LD symbols are resolved.
36+
//
37+
// The alternative is to use a Part Definition (PR). In this case, the data (in
38+
// a text record) is associated with the part. When binding, only the data of
39+
// referenced PRs is pulled into the resulting binary.
40+
//
41+
// Both approaches are used. SD, ED, and PR elements are modelled by nested
42+
// MCSectionGOFF instances, while LD elements are associated with MCSymbolGOFF
43+
// instances.
44+
45+
// Attributes for SD symbols.
46+
struct SDAttr {
47+
GOFF::ESDTaskingBehavior TaskingBehavior = GOFF::ESD_TA_Unspecified;
48+
GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified;
49+
};
50+
51+
// Attributes for ED symbols.
52+
struct EDAttr {
53+
bool IsReadOnly = false;
54+
GOFF::ESDRmode Rmode;
55+
GOFF::ESDNameSpaceId NameSpace = GOFF::ESD_NS_NormalName;
56+
GOFF::ESDTextStyle TextStyle = GOFF::ESD_TS_ByteOriented;
57+
GOFF::ESDBindingAlgorithm BindAlgorithm = GOFF::ESD_BA_Concatenate;
58+
GOFF::ESDLoadingBehavior LoadBehavior = GOFF::ESD_LB_Initial;
59+
GOFF::ESDReserveQwords ReservedQwords = GOFF::ESD_RQ_0;
60+
GOFF::ESDAlignment Alignment = GOFF::ESD_ALIGN_Doubleword;
61+
uint8_t FillByteValue = 0;
62+
};
63+
64+
// Attributes for LD symbols.
65+
struct LDAttr {
66+
bool IsRenamable = false;
67+
GOFF::ESDExecutable Executable = GOFF::ESD_EXE_Unspecified;
68+
GOFF::ESDBindingStrength BindingStrength = GOFF::ESD_BST_Strong;
69+
GOFF::ESDLinkageType Linkage = GOFF::ESD_LT_XPLink;
70+
GOFF::ESDAmode Amode;
71+
GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified;
72+
};
73+
74+
// Attributes for PR symbols.
75+
struct PRAttr {
76+
bool IsRenamable = false;
77+
GOFF::ESDExecutable Executable = GOFF::ESD_EXE_Unspecified;
78+
GOFF::ESDLinkageType Linkage = GOFF::ESD_LT_XPLink;
79+
GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified;
80+
uint32_t SortKey = 0;
81+
};
82+
83+
// Predefined GOFF class names.
84+
constexpr StringLiteral CLASS_CODE = "C_CODE64";
85+
constexpr StringLiteral CLASS_WSA = "C_WSA64";
86+
constexpr StringLiteral CLASS_DATA = "C_DATA64";
87+
constexpr StringLiteral CLASS_PPA2 = "C_@@QPPA2";
88+
89+
} // namespace GOFF
90+
} // namespace llvm
91+
92+
#endif

llvm/include/llvm/MC/MCGOFFStreamer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace llvm {
1616
class GOFFObjectWriter;
1717

1818
class MCGOFFStreamer : public MCObjectStreamer {
19+
1920
public:
2021
MCGOFFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
2122
std::unique_ptr<MCObjectWriter> OW,
@@ -25,6 +26,8 @@ class MCGOFFStreamer : public MCObjectStreamer {
2526

2627
~MCGOFFStreamer() override;
2728

29+
void changeSection(MCSection *Section, uint32_t Subsection = 0) override;
30+
2831
GOFFObjectWriter &getWriter();
2932

3033
bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {

llvm/include/llvm/MC/MCObjectFileInfo.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,6 @@ class LLVM_ABI MCObjectFileInfo {
231231
MCSection *GLJMPSection = nullptr;
232232

233233
// GOFF specific sections.
234-
MCSection *PPA1Section = nullptr;
235-
MCSection *PPA2Section = nullptr;
236234
MCSection *PPA2ListSection = nullptr;
237235
MCSection *ADASection = nullptr;
238236
MCSection *IDRLSection = nullptr;
@@ -439,8 +437,6 @@ class LLVM_ABI MCObjectFileInfo {
439437
MCSection *getGLJMPSection() const { return GLJMPSection; }
440438

441439
// GOFF specific sections.
442-
MCSection *getPPA1Section() const { return PPA1Section; }
443-
MCSection *getPPA2Section() const { return PPA2Section; }
444440
MCSection *getPPA2ListSection() const { return PPA2ListSection; }
445441
MCSection *getADASection() const { return ADASection; }
446442
MCSection *getIDRLSection() const { return IDRLSection; }

llvm/include/llvm/MC/MCSectionGOFF.h

Lines changed: 71 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,34 +16,95 @@
1616
#define LLVM_MC_MCSECTIONGOFF_H
1717

1818
#include "llvm/BinaryFormat/GOFF.h"
19+
#include "llvm/MC/MCGOFFAttributes.h"
1920
#include "llvm/MC/MCSection.h"
21+
#include "llvm/Support/ErrorHandling.h"
2022
#include "llvm/Support/raw_ostream.h"
2123

2224
namespace llvm {
2325

2426
class MCExpr;
2527

2628
class MCSectionGOFF final : public MCSection {
27-
private:
28-
MCSection *Parent;
29-
uint32_t Subsection;
29+
// Parent of this section. Implies that the parent is emitted first.
30+
MCSectionGOFF *Parent;
31+
32+
// The attributes of the GOFF symbols.
33+
union {
34+
GOFF::SDAttr SDAttributes;
35+
GOFF::EDAttr EDAttributes;
36+
GOFF::PRAttr PRAttributes;
37+
};
38+
39+
// The type of this section.
40+
GOFF::ESDSymbolType SymbolType;
41+
42+
// Indicates that the PR symbol needs to set the length of the section to a
43+
// non-zero value. This is only a problem with the ADA PR - the binder will
44+
// generate an error in this case.
45+
unsigned RequiresNonZeroLength : 1;
46+
47+
// Set to true if the section definition was already emitted.
48+
mutable unsigned Emitted : 1;
3049

3150
friend class MCContext;
32-
MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, uint32_t Sub)
51+
friend class MCSymbolGOFF;
52+
53+
MCSectionGOFF(StringRef Name, SectionKind K, GOFF::SDAttr SDAttributes,
54+
MCSectionGOFF *Parent)
55+
: MCSection(SV_GOFF, Name, K.isText(), /*IsVirtual=*/false, nullptr),
56+
Parent(Parent), SDAttributes(SDAttributes),
57+
SymbolType(GOFF::ESD_ST_SectionDefinition), RequiresNonZeroLength(0),
58+
Emitted(0) {}
59+
60+
MCSectionGOFF(StringRef Name, SectionKind K, GOFF::EDAttr EDAttributes,
61+
MCSectionGOFF *Parent)
62+
: MCSection(SV_GOFF, Name, K.isText(), /*IsVirtual=*/false, nullptr),
63+
Parent(Parent), EDAttributes(EDAttributes),
64+
SymbolType(GOFF::ESD_ST_ElementDefinition), RequiresNonZeroLength(0),
65+
Emitted(0) {}
66+
67+
MCSectionGOFF(StringRef Name, SectionKind K, GOFF::PRAttr PRAttributes,
68+
MCSectionGOFF *Parent)
3369
: MCSection(SV_GOFF, Name, K.isText(), /*IsVirtual=*/false, nullptr),
34-
Parent(P), Subsection(Sub) {}
70+
Parent(Parent), PRAttributes(PRAttributes),
71+
SymbolType(GOFF::ESD_ST_PartReference), RequiresNonZeroLength(0),
72+
Emitted(0) {}
3573

3674
public:
3775
void printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
3876
raw_ostream &OS,
39-
uint32_t /*Subsection*/) const override {
40-
OS << "\t.section\t\"" << getName() << "\"\n";
41-
}
77+
uint32_t Subsection) const override;
4278

4379
bool useCodeAlign() const override { return false; }
4480

45-
MCSection *getParent() const { return Parent; }
46-
uint32_t getSubsection() const { return Subsection; }
81+
// Return the parent section.
82+
MCSectionGOFF *getParent() const { return Parent; }
83+
84+
// Returns the type of this section.
85+
GOFF::ESDSymbolType getSymbolType() const { return SymbolType; }
86+
87+
bool isSD() const { return SymbolType == GOFF::ESD_ST_SectionDefinition; }
88+
bool isED() const { return SymbolType == GOFF::ESD_ST_ElementDefinition; }
89+
bool isPR() const { return SymbolType == GOFF::ESD_ST_PartReference; }
90+
91+
// Accessors to the attributes.
92+
GOFF::SDAttr getSDAttributes() const {
93+
assert(isSD() && "Not a SD section");
94+
return SDAttributes;
95+
}
96+
GOFF::EDAttr getEDAttributes() const {
97+
assert(isED() && "Not a ED section");
98+
return EDAttributes;
99+
}
100+
GOFF::PRAttr getPRAttributes() const {
101+
assert(isPR() && "Not a PR section");
102+
return PRAttributes;
103+
}
104+
105+
bool requiresNonZeroLength() const { return RequiresNonZeroLength; }
106+
107+
void setName(StringRef SectionName) { Name = SectionName; }
47108

48109
static bool classof(const MCSection *S) { return S->getVariant() == SV_GOFF; }
49110
};

0 commit comments

Comments
 (0)