-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[GOFF] Write out relocations in the GOFF writer #167054
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
base: users/redstar/goffwriter-5
Are you sure you want to change the base?
Conversation
Add support for writing relocations. Since the symbol numbering is only available after the symbols are written, the relocations are collected in a vector. At write time, the relocations are converted using the symbols ids, compressed and written out. A relocation data record is limited to 32K-1 bytes, which requires making sure that larger relocation data is written into multiple records.
|
@llvm/pr-subscribers-llvm-binary-utilities @llvm/pr-subscribers-llvm-mc Author: Kai Nacke (redstar) ChangesAdd support for writing relocations. Since the symbol numbering is only available after the symbols are written, the relocations are collected in a vector. At write time, the relocations are converted using the symbols ids, compressed and written out. A relocation data record is limited to 32K-1 bytes, which requires making sure that larger relocation data is written into multiple records. Patch is 21.28 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/167054.diff 7 Files Affected:
diff --git a/llvm/include/llvm/BinaryFormat/GOFF.h b/llvm/include/llvm/BinaryFormat/GOFF.h
index 49d2809cb6524..08bdb5d624fca 100644
--- a/llvm/include/llvm/BinaryFormat/GOFF.h
+++ b/llvm/include/llvm/BinaryFormat/GOFF.h
@@ -157,6 +157,32 @@ enum ESDAlignment : uint8_t {
ESD_ALIGN_4Kpage = 12,
};
+enum RLDReferenceType : uint8_t {
+ RLD_RT_RAddress = 0,
+ RLD_RT_ROffset = 1,
+ RLD_RT_RLength = 2,
+ RLD_RT_RRelativeImmediate = 6,
+ RLD_RT_RTypeConstant = 7,
+ RLD_RT_RLongDisplacement = 9,
+};
+
+enum RLDReferentType : uint8_t {
+ RLD_RO_Label = 0,
+ RLD_RO_Element = 1,
+ RLD_RO_Class = 2,
+ RLD_RO_Part = 3,
+};
+
+enum RLDAction : uint8_t {
+ RLD_ACT_Add = 0,
+ RLD_ACT_Subtract = 1,
+};
+
+enum RLDFetchStore : uint8_t {
+ RLD_FS_Fetch = 0,
+ RLD_FS_Store = 1
+};
+
enum ENDEntryPointRequest : uint8_t {
END_EPR_None = 0,
END_EPR_EsdidOffset = 1,
diff --git a/llvm/include/llvm/MC/MCGOFFObjectWriter.h b/llvm/include/llvm/MC/MCGOFFObjectWriter.h
index ec07637dd2847..408d432a8f54f 100644
--- a/llvm/include/llvm/MC/MCGOFFObjectWriter.h
+++ b/llvm/include/llvm/MC/MCGOFFObjectWriter.h
@@ -11,9 +11,13 @@
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCValue.h"
+#include <memory>
+#include <vector>
namespace llvm {
class MCObjectWriter;
+class MCSectionGOFF;
+class MCSymbolGOFF;
class raw_pwrite_stream;
class MCGOFFObjectTargetWriter : public MCObjectTargetWriter {
@@ -21,8 +25,19 @@ class MCGOFFObjectTargetWriter : public MCObjectTargetWriter {
MCGOFFObjectTargetWriter() = default;
public:
+ enum RLDRelocationType {
+ Reloc_Type_ACon = 0x1, // General address.
+ Reloc_Type_RelImm = 0x2, // Relative-immediate address.
+ Reloc_Type_QCon = 0x3, // Offset of symbol in class.
+ Reloc_Type_VCon = 0x4, // Address of external symbol.
+ Reloc_Type_RCon = 0x5, // PSECT of symbol.
+ };
+
~MCGOFFObjectTargetWriter() override = default;
+ virtual unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup,
+ bool IsPCRel) const = 0;
+
Triple::ObjectFormatType getFormat() const override { return Triple::GOFF; }
static bool classof(const MCObjectTargetWriter *W) {
@@ -30,6 +45,23 @@ class MCGOFFObjectTargetWriter : public MCObjectTargetWriter {
}
};
+struct GOFFSavedRelocationEntry {
+ const MCSectionGOFF *Section;
+ const MCSymbolGOFF *SymA;
+ const MCSymbolGOFF *SymB;
+ unsigned RelocType;
+ uint64_t FixupOffset;
+ uint32_t Length;
+ uint64_t FixedValue; // Info only.
+
+ GOFFSavedRelocationEntry(const MCSectionGOFF *Section,
+ const MCSymbolGOFF *SymA, const MCSymbolGOFF *SymB,
+ unsigned RelocType, uint64_t FixupOffset,
+ uint32_t Length, uint64_t FixedValue)
+ : Section(Section), SymA(SymA), SymB(SymB), RelocType(RelocType),
+ FixupOffset(FixupOffset), Length(Length), FixedValue(FixedValue) {}
+};
+
class GOFFObjectWriter : public MCObjectWriter {
// The target specific GOFF writer instance.
std::unique_ptr<MCGOFFObjectTargetWriter> TargetObjectWriter;
@@ -37,6 +69,9 @@ class GOFFObjectWriter : public MCObjectWriter {
// The stream used to write the GOFF records.
raw_pwrite_stream &OS;
+ // Saved relocation data.
+ std::vector<GOFFSavedRelocationEntry> SavedRelocs;
+
public:
GOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW,
raw_pwrite_stream &OS);
@@ -44,7 +79,7 @@ class GOFFObjectWriter : public MCObjectWriter {
// Implementation of the MCObjectWriter interface.
void recordRelocation(const MCFragment &F, const MCFixup &Fixup,
- MCValue Target, uint64_t &FixedValue) override {}
+ MCValue Target, uint64_t &FixedValue) override;
uint64_t writeObject() override;
};
diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp
index 07aecf13bce37..b4640ed7871f0 100644
--- a/llvm/lib/MC/GOFFObjectWriter.cpp
+++ b/llvm/lib/MC/GOFFObjectWriter.cpp
@@ -10,7 +10,9 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/SmallVector.h"
#include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCGOFFAttributes.h"
#include "llvm/MC/MCGOFFObjectWriter.h"
@@ -280,13 +282,42 @@ class GOFFSymbol {
}
};
+// A GOFFRelocationEntry describes a single relocation.
+struct GOFFRelocationEntry {
+ uint32_t REsdId; // The R pointer.
+ uint32_t PEsdId; // The P pointer.
+ uint64_t POffset; // The offset within the element described by the P pointer.
+
+ uint32_t TargetLength; // The byte length of the target field.
+
+ // Details of the relocation.
+ GOFF::RLDReferenceType ReferenceType : 4;
+ GOFF::RLDReferentType ReferentType : 2;
+ GOFF::RLDAction Action : 1;
+ GOFF::RLDFetchStore FetchStore : 1;
+
+ GOFFRelocationEntry() = default;
+ GOFFRelocationEntry(uint32_t REsdId, uint32_t PEsdId, uint64_t POffset,
+ GOFF::RLDReferenceType ReferenceType,
+ GOFF::RLDReferentType ReferentType,
+ GOFF::RLDAction Action, GOFF::RLDFetchStore FetchStore,
+ uint32_t TargetLength)
+ : REsdId(REsdId), PEsdId(PEsdId), POffset(POffset),
+ TargetLength(TargetLength), ReferenceType(ReferenceType),
+ ReferentType(ReferentType), Action(Action), FetchStore(FetchStore) {}
+};
+
class GOFFWriter {
GOFFOstream OS;
MCAssembler &Asm;
+ /// Saved relocation data collected in recordRelocations().
+ const std::vector<GOFFSavedRelocationEntry> &SavedRelocs;
+
void writeHeader();
void writeSymbol(const GOFFSymbol &Symbol);
void writeText(const MCSectionGOFF *MC);
+ void writeRelocations();
void writeEnd();
void defineSectionSymbols(const MCSectionGOFF &Section);
@@ -295,13 +326,15 @@ class GOFFWriter {
void defineSymbols();
public:
- GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm);
+ GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm,
+ const std::vector<GOFFSavedRelocationEntry> &SavedRelocs);
uint64_t writeObject();
};
} // namespace
-GOFFWriter::GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm)
- : OS(OS), Asm(Asm) {}
+GOFFWriter::GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm,
+ const std::vector<GOFFSavedRelocationEntry> &SavedRelocs)
+ : OS(OS), Asm(Asm), SavedRelocs(SavedRelocs) {}
void GOFFWriter::defineSectionSymbols(const MCSectionGOFF &Section) {
if (Section.isSD()) {
@@ -502,6 +535,169 @@ void GOFFWriter::writeText(const MCSectionGOFF *Section) {
Asm.writeSectionData(S, Section);
}
+namespace {
+// RelocDataItemBuffer provides a static buffer for relocation data items.
+class RelocDataItemBuffer {
+ char Buffer[GOFF::MaxDataLength];
+ char *Ptr;
+
+public:
+ RelocDataItemBuffer() : Ptr(Buffer) {}
+ const char *data() { return Buffer; }
+ size_t size() { return Ptr - Buffer; }
+ void reset() { Ptr = Buffer; }
+ bool fits(size_t S) { return size() + S < GOFF::MaxDataLength; }
+ template <typename T> void writebe(T Val) {
+ assert(fits(sizeof(T)) && "Out-of-bounds write");
+ support::endian::write<T, llvm::endianness::big>(Ptr, Val);
+ Ptr += sizeof(T);
+ }
+};
+} // namespace
+
+void GOFFWriter::writeRelocations() {
+ // Transform a GOFFSavedRelocationEntry to 1 or 2 GOFFRelocationEntry
+ // instances. An expression like SymA - SymB + Const is implemented by storing
+ // Const in the memory (aka the FixedValue), and then having a relocation to
+ // add SymA, and another relocation to subtract SymB.
+ std::vector<GOFFRelocationEntry> Relocations;
+ for (auto &RelocEntry : SavedRelocs) {
+ auto *PSection = RelocEntry.Section;
+ auto RelocType = RelocEntry.RelocType;
+ auto *A = RelocEntry.SymA;
+ auto *B = RelocEntry.SymB;
+ auto FixupOffset = RelocEntry.FixupOffset;
+ auto Length = RelocEntry.Length;
+
+ auto GetRptr = [](const MCSymbolGOFF *Sym) -> uint32_t {
+ if (Sym->isTemporary())
+ return static_cast<MCSectionGOFF &>(Sym->getSection())
+ .getBeginSymbol()
+ ->getIndex();
+ return Sym->getIndex();
+ };
+
+ const uint32_t Pptr = PSection->getOrdinal();
+ uint32_t RptrA = GetRptr(A);
+ uint32_t RptrB = B ? GetRptr(B) : 0;
+
+ // UseQCon causes class offsets versus absolute addresses to be used. This
+ // is analogous to using QCONs in older OBJ object file format.
+ bool UseQCon = RelocType == MCGOFFObjectTargetWriter::Reloc_Type_QCon;
+
+ GOFF::RLDFetchStore FetchStore =
+ (RelocType == MCGOFFObjectTargetWriter::Reloc_Type_RCon ||
+ RelocType == MCGOFFObjectTargetWriter::Reloc_Type_VCon)
+ ? GOFF::RLDFetchStore::RLD_FS_Store
+ : GOFF::RLDFetchStore::RLD_FS_Fetch;
+ assert(FetchStore == GOFF::RLDFetchStore::RLD_FS_Fetch ||
+ RptrB == 0 && "No dependent relocations expected");
+
+ enum GOFF::RLDReferenceType ReferenceType = GOFF::RLD_RT_RAddress;
+ enum GOFF::RLDReferentType ReferentType = GOFF::RLD_RO_Label;
+ if (UseQCon) {
+ ReferenceType = GOFF::RLD_RT_ROffset;
+ ReferentType = GOFF::RLD_RO_Class;
+ }
+ if (RelocType == MCGOFFObjectTargetWriter::Reloc_Type_RCon)
+ ReferenceType = GOFF::RLD_RT_RTypeConstant;
+
+ if (RptrA) {
+ LLVM_DEBUG(dbgs() << "Reloc A: " << (UseQCon ? "QCon" : "ACon")
+ << " Rptr: " << RptrA << " Pptr: " << Pptr
+ << " Offset: " << FixupOffset
+ << " Fixed Imm: " << RelocEntry.FixedValue << "\n");
+ Relocations.emplace_back(RptrA, Pptr, FixupOffset, ReferenceType,
+ ReferentType, GOFF::RLD_ACT_Add, FetchStore,
+ Length);
+ }
+ if (RptrB) {
+ LLVM_DEBUG(dbgs() << "Reloc B: " << (UseQCon ? "QCon" : "ACon")
+ << " Rptr: " << RptrA << " Pptr: " << Pptr
+ << " Offset: " << FixupOffset
+ << " Fixed Imm: " << RelocEntry.FixedValue << "\n");
+ Relocations.emplace_back(RptrB, Pptr, FixupOffset, ReferenceType,
+ ReferentType, GOFF::RLD_ACT_Subtract,
+ GOFF::RLDFetchStore::RLD_FS_Fetch, Length);
+ }
+ }
+
+ // Sort relocation data items by the P pointer to save space.
+ std::sort(
+ Relocations.begin(), Relocations.end(),
+ [](const GOFFRelocationEntry &Left, const GOFFRelocationEntry &Right) {
+ return std::tie(Left.PEsdId, Left.REsdId, Left.POffset) <
+ std::tie(Right.PEsdId, Right.REsdId, Right.POffset);
+ });
+
+ // Construct the compressed relocation data items, and write them out.
+ RelocDataItemBuffer Buffer;
+ for (auto I = Relocations.begin(), E = Relocations.end(); I != E;) {
+ Buffer.reset();
+
+ uint32_t PrevResdId = -1;
+ uint32_t PrevPesdId = -1;
+ uint64_t PrevPOffset = -1;
+ for (; I != E; ++I) {
+ const GOFFRelocationEntry &Rel = *I;
+
+ bool SameREsdId = (Rel.REsdId == PrevResdId);
+ bool SamePEsdId = (Rel.PEsdId == PrevPesdId);
+ bool SamePOffset = (Rel.POffset == PrevPOffset);
+ bool EightByteOffset = ((Rel.POffset >> 32) & 0xffffffff);
+
+ // Calculate size of relocation data item, and check if it still fits into
+ // the record.
+ size_t ItemSize = 8; // Smallest size of a relocation data item.
+ if (!SameREsdId)
+ ItemSize += 4;
+ if (!SamePEsdId)
+ ItemSize += 4;
+ if (!SamePOffset)
+ ItemSize += (EightByteOffset ? 8 : 4);
+ if (!Buffer.fits(ItemSize))
+ break;
+
+ GOFF::Flags RelocFlags[6];
+ RelocFlags[0].set(0, 1, SameREsdId);
+ RelocFlags[0].set(1, 1, SamePEsdId);
+ RelocFlags[0].set(2, 1, SamePOffset);
+ RelocFlags[0].set(6, 1, EightByteOffset);
+
+ RelocFlags[1].set(0, 4, Rel.ReferenceType);
+ RelocFlags[1].set(4, 4, Rel.ReferentType);
+
+ RelocFlags[2].set(0, 7, Rel.Action);
+ RelocFlags[2].set(7, 1, Rel.FetchStore);
+
+ RelocFlags[4].set(0, 8, Rel.TargetLength);
+
+ for (auto F : RelocFlags)
+ Buffer.writebe<uint8_t>(F);
+ Buffer.writebe<uint16_t>(0); // Reserved.
+ if (!SameREsdId)
+ Buffer.writebe<uint32_t>(Rel.REsdId);
+ if (!SamePEsdId)
+ Buffer.writebe<uint32_t>(Rel.PEsdId);
+ if (!SamePOffset) {
+ if (EightByteOffset)
+ Buffer.writebe<uint64_t>(Rel.POffset);
+ else
+ Buffer.writebe<uint32_t>(Rel.POffset);
+ }
+
+ PrevResdId = Rel.REsdId;
+ PrevPesdId = Rel.PEsdId;
+ PrevPOffset = Rel.POffset;
+ }
+
+ OS.newRecord(GOFF::RT_RLD);
+ OS.writebe<uint8_t>(0); // Reserved.
+ OS.writebe<uint16_t>(Buffer.size()); // Length (of the relocation data).
+ OS.write(Buffer.data(), Buffer.size()); // Relocation Directory Data Items.
+ }
+}
+
void GOFFWriter::writeEnd() {
uint8_t F = GOFF::END_EPR_None;
uint8_t AMODE = 0;
@@ -528,6 +724,8 @@ uint64_t GOFFWriter::writeObject() {
for (const MCSection &Section : Asm)
writeText(static_cast<const MCSectionGOFF *>(&Section));
+ writeRelocations();
+
writeEnd();
// Make sure all records are written.
@@ -545,8 +743,68 @@ GOFFObjectWriter::GOFFObjectWriter(
GOFFObjectWriter::~GOFFObjectWriter() = default;
+void GOFFObjectWriter::recordRelocation(const MCFragment &F,
+ const MCFixup &Fixup, MCValue Target,
+ uint64_t &FixedValue) {
+ const MCFixupKindInfo &FKI =
+ Asm->getBackend().getFixupKindInfo(Fixup.getKind());
+ const uint32_t Length = FKI.TargetSize / 8;
+ assert(FKI.TargetSize % 8 == 0 && "Target Size not multiple of 8");
+ const uint64_t FixupOffset = Asm->getFragmentOffset(F) + Fixup.getOffset();
+ bool IsPCRel = Fixup.isPCRel();
+
+ unsigned RelocType = TargetObjectWriter->getRelocType(Target, Fixup, IsPCRel);
+
+ const MCSectionGOFF *PSection = static_cast<MCSectionGOFF *>(F.getParent());
+ const auto &A = *static_cast<const MCSymbolGOFF *>(Target.getAddSym());
+ const MCSymbolGOFF *B = static_cast<const MCSymbolGOFF *>(Target.getSubSym());
+ if (RelocType == MCGOFFObjectTargetWriter::Reloc_Type_RelImm) {
+ if (A.isUndefined()) {
+ Asm->reportError(
+ Fixup.getLoc(),
+ Twine("symbol ")
+ .concat(A.getName())
+ .concat(" must be defined for a relative immediate relocation"));
+ return;
+ }
+ if (&A.getSection() != PSection) {
+ Asm->reportError(Fixup.getLoc(),
+ Twine("relative immediate relocation section mismatch: ")
+ .concat(A.getSection().getName())
+ .concat(" of symbol ")
+ .concat(A.getName())
+ .concat(" <-> ")
+ .concat(PSection->getName()));
+ return;
+ }
+ if (B) {
+ Asm->reportError(
+ Fixup.getLoc(),
+ Twine("subtractive symbol ")
+ .concat(B->getName())
+ .concat(" not supported for a relative immediate relocation"));
+ return;
+ }
+ FixedValue = Asm->getSymbolOffset(A) - FixupOffset + Target.getConstant();
+ return;
+ }
+ FixedValue = Target.getConstant();
+
+ // The symbol only has a section-relative offset if it is a temporary symbol.
+ FixedValue += A.isTemporary() ? Asm->getSymbolOffset(A) : 0;
+ A.setUsedInReloc();
+ if (B) {
+ FixedValue -= B->isTemporary() ? Asm->getSymbolOffset(*B) : 0;
+ B->setUsedInReloc();
+ }
+
+ // Save relocation data for later writing.
+ SavedRelocs.emplace_back(PSection, &A, B, RelocType, FixupOffset, Length,
+ FixedValue);
+}
+
uint64_t GOFFObjectWriter::writeObject() {
- uint64_t Size = GOFFWriter(OS, *Asm).writeObject();
+ uint64_t Size = GOFFWriter(OS, *Asm, SavedRelocs).writeObject();
return Size;
}
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZGOFFObjectWriter.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZGOFFObjectWriter.cpp
index 205066814fbd0..8c042d1dbb014 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZGOFFObjectWriter.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZGOFFObjectWriter.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/SystemZMCTargetDesc.h"
+#include "SystemZMCAsmInfo.h"
#include "llvm/MC/MCGOFFObjectWriter.h"
#include <memory>
@@ -16,12 +17,35 @@ namespace {
class SystemZGOFFObjectWriter : public MCGOFFObjectTargetWriter {
public:
SystemZGOFFObjectWriter();
+
+ unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup,
+ bool IsPCRel) const override;
};
} // end anonymous namespace
SystemZGOFFObjectWriter::SystemZGOFFObjectWriter()
: MCGOFFObjectTargetWriter() {}
+unsigned SystemZGOFFObjectWriter::getRelocType(const MCValue &Target,
+ const MCFixup &Fixup,
+ bool IsPCRel) const {
+ switch (Target.getSpecifier()) {
+ case SystemZ::S_PLT: // TODO This doen't make sense.
+ return Reloc_Type_RelImm;
+ case SystemZ::S_RCon:
+ return Reloc_Type_RCon;
+ case SystemZ::S_VCon:
+ return Reloc_Type_VCon;
+ case SystemZ::S_QCon:
+ return Reloc_Type_QCon;
+ case SystemZ::S_None:
+ if (IsPCRel)
+ return Reloc_Type_RelImm;
+ return Reloc_Type_ACon;
+ }
+ llvm_unreachable("Modifier not supported");
+}
+
std::unique_ptr<MCObjectTargetWriter> llvm::createSystemZGOFFObjectWriter() {
return std::make_unique<SystemZGOFFObjectWriter>();
}
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h
index 11c2833b8ada8..668158b896856 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h
@@ -51,6 +51,7 @@ enum {
// https://www.ibm.com/docs/en/hla-and-tf/1.6?topic=value-address-constants
S_RCon, // Address of ADA of symbol.
S_VCon, // Address of external function symbol.
+ S_QCon, // Class-based offset.
};
} // namespace SystemZ
diff --git a/llvm/test/CodeGen/SystemZ/zos-section-1.ll b/llvm/test/CodeGen/SystemZ/zos-section-1.ll
index cae371b07d0eb..f4e245addc2c3 100644
--- a/llvm/test/CodeGen/SystemZ/zos-section-1.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-section-1.ll
@@ -145,9 +145,22 @@ entry:
; CHECK: 000550 03 10 00 01 [[BIDRL]] 00 00 00 00 00 00 00 00
; CHECK-NEXT: 000560 00 00 00 00 00 00 00 {{..}} {{.*}}
+; The relocation data directory.
+; CHECK: 0005a0 03 21 00 00 00 5c 00 00 02 00 04 00 00 00 00 00
+; CHECK-NEXT: 0005b0 00 08 00 00 00 02 00 00 00 5a 60 00 00 00 04 00
+; CHECK-NEXT: 0005c0 00 00 00 00 00 09 00 00 00 00 08 00 00 00 00 00
+; CHECK-NEXT: 0005d0 00 08 00 00 00 04 00 00 00 00 60 00 02 00 08 00
+; CHECK-NEXT: 0005e0 00 00 00 00 00 09 20 70 01 00 08 00 00 00 00 00
+; Continuation of the relocation data directory.
+; CHECK-NEXT: 0005f0 03 22 00 00 0b 00 00 00 06 c0 00 01 00 08 00 00
+; CHECK-NEXT: 000600 00 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000610 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000620 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000630 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
; End record.
-; CHECK: 0005a0 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 0005b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 0005c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 0005d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 0005e0 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
diff --git a/llvm/test/CodeGen/SystemZ/zos-section-2.ll b/llvm/test/CodeGen/SystemZ/zos-section-2.ll
index f59bace65ca73..d3eb6d9505340 1006...
[truncated]
|
|
With this and the previous PR, it is now possible to compile simple functions, and bind them together to an executable. |
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
tltao
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM for the most part aside from some minor comments.
llvm/lib/Target/SystemZ/MCTargetDesc/SystemZGOFFObjectWriter.cpp
Outdated
Show resolved
Hide resolved
llvm/lib/Target/SystemZ/MCTargetDesc/SystemZGOFFObjectWriter.cpp
Outdated
Show resolved
Hide resolved
| // https://www.ibm.com/docs/en/hla-and-tf/1.6?topic=value-address-constants | ||
| S_RCon, // Address of ADA of symbol. | ||
| S_VCon, // Address of external function symbol. | ||
| S_QCon, // Class-based offset. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess nobody is emitting this yet? Would be good to have an exploiter for test purposes at least ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, there is no user yet. It is requires for the ctor/dtor lists. I think about a test until then...
| const MCFixup &Fixup, | ||
| bool IsPCRel) const { | ||
| switch (Target.getSpecifier()) { | ||
| case SystemZ::S_PLT: // TODO This doen't make sense. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should fix this where it is emitted instead. We shouldn't generate the S_PLT specifier for XPLink at all.
llvm/lib/MC/GOFFObjectWriter.cpp
Outdated
| // instances. An expression like SymA - SymB + Const is implemented by storing | ||
| // Const in the memory (aka the FixedValue), and then having a relocation to | ||
| // add SymA, and another relocation to subtract SymB. | ||
| std::vector<GOFFRelocationEntry> Relocations; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a bit unfortunate that we have two temporary relocation buffers; the GOFFSavedRelocationEntry vector in the caller and this GOFFRelocationEntry here. Would there be a way to avoid this second copy? E.g. the caller should already be able to make the decision to create two entries, right? We'd just have to keep MCSymbolGOFF pointers instead of EsdIds, but those could be dereferenced on the fly here, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reworked the code to just use one vector. I added the id fields to the structure, and initialize them later. Since retrieving the the id of a symbol includes a condition, I think it is worthwhile to cache the id in the structure.
llvm/lib/MC/GOFFObjectWriter.cpp
Outdated
|
|
||
| uint64_t GOFFObjectWriter::writeObject() { | ||
| uint64_t Size = GOFFWriter(OS, *Asm).writeObject(); | ||
| uint64_t Size = GOFFWriter(OS, *Asm, SavedRelocs).writeObject(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Precedent e.g. from ELF would be to pass a reference to the whole GOFFObjectWriter to the GOFFWriter rather than just a single field. Not sure which is really better here ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is an interesting style question. The ELF solution also requires to have all fields public, because it is difficult to make a class in an anonymous namespace a friend of a class in a header file. I prefer passing the required fields instead of making the fields public.
Looking forward, I do not see that I need to pass more fields from the GOFFObjectWriter into the GOFFWriter, so the current solution looks reasonable to me.
Information can be retrieved from `Fixup`.
Add support for writing relocations. Since the symbol numbering is only available after the symbols are written, the relocations are collected in a vector. At write time, the relocations are converted using the symbols ids, compressed and written out. A relocation data record is limited to 32K-1 bytes, which requires making sure that larger relocation data is written into multiple records.