LLVM 24.0.0git
GOFFObjectWriter.cpp
Go to the documentation of this file.
1//===- lib/MC/GOFFObjectWriter.cpp - GOFF File Writer ---------------------===//
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// This file implements GOFF object file writer information.
10//
11//===----------------------------------------------------------------------===//
12
15#include "llvm/MC/MCAssembler.h"
21#include "llvm/MC/MCValue.h"
23#include "llvm/Support/Debug.h"
24#include "llvm/Support/Endian.h"
26
27using namespace llvm;
28
29#define DEBUG_TYPE "goff-writer"
30
31namespace {
32// Common flag values on records.
33
34// Flag: This record is continued.
35constexpr uint8_t RecContinued = GOFF::Flags(7, 1, 1);
36
37// Flag: This record is a continuation.
38constexpr uint8_t RecContinuation = GOFF::Flags(6, 1, 1);
39
40// The GOFFOstream is responsible to write the data into the fixed physical
41// records of the format. A user of this class announces the begin of a new
42// logical record. While writing the payload, the physical records are created
43// for the data. Possible fill bytes at the end of a physical record are written
44// automatically. In principle, the GOFFOstream is agnostic of the endianness of
45// the payload. However, it also supports writing data in big endian byte order.
46//
47// The physical records use the flag field to indicate if the there is a
48// successor and predecessor record. To be able to set these flags while
49// writing, the basic implementation idea is to always buffer the last seen
50// physical record.
51class GOFFOstream {
52 /// The underlying raw_pwrite_stream.
54
55 /// The number of logical records emitted so far.
56 uint32_t LogicalRecords = 0;
57
58 /// The number of physical records emitted so far.
59 uint32_t PhysicalRecords = 0;
60
61 /// The size of the buffer. Same as the payload size of a physical record.
62 static constexpr uint8_t BufferSize = GOFF::PayloadLength;
63
64 /// Current position in buffer.
65 char *BufferPtr = Buffer;
66
67 /// Static allocated buffer for the stream.
68 char Buffer[BufferSize];
69
70 /// The type of the current logical record, and the flags (aka continued and
71 /// continuation indicators) for the previous (physical) record.
72 uint8_t TypeAndFlags = 0;
73
74public:
75 GOFFOstream(raw_pwrite_stream &OS);
76 ~GOFFOstream();
77
78 raw_pwrite_stream &getOS() { return OS; }
79 size_t getWrittenSize() const { return PhysicalRecords * GOFF::RecordLength; }
80 uint32_t getNumLogicalRecords() { return LogicalRecords; }
81
82 /// Write the specified bytes.
83 void write(const char *Ptr, size_t Size);
84
85 /// Write zeroes, up to a maximum of 16 bytes.
86 void write_zeros(unsigned NumZeros);
87
88 /// Support for endian-specific data.
89 template <typename value_type> void writebe(value_type Value) {
90 Value =
92 write((const char *)&Value, sizeof(value_type));
93 }
94
95 /// Begin a new logical record. Implies finalizing the previous record.
96 void newRecord(GOFF::RecordType Type);
97
98 /// Ends a logical record.
99 void finalizeRecord();
100
101private:
102 /// Updates the continued/continuation flags, and writes the record prefix of
103 /// a physical record.
104 void updateFlagsAndWritePrefix(bool IsContinued);
105
106 /// Returns the remaining size in the buffer.
107 size_t getRemainingSize();
108};
109} // namespace
110
111GOFFOstream::GOFFOstream(raw_pwrite_stream &OS) : OS(OS) {}
112
113GOFFOstream::~GOFFOstream() { finalizeRecord(); }
114
115void GOFFOstream::updateFlagsAndWritePrefix(bool IsContinued) {
116 // Update the flags based on the previous state and the flag IsContinued.
117 if (TypeAndFlags & RecContinued)
118 TypeAndFlags |= RecContinuation;
119 if (IsContinued)
120 TypeAndFlags |= RecContinued;
121 else
122 TypeAndFlags &= ~RecContinued;
123
124 OS << static_cast<unsigned char>(GOFF::PTVPrefix) // Record Type
125 << static_cast<unsigned char>(TypeAndFlags) // Continuation
126 << static_cast<unsigned char>(0); // Version
127
128 ++PhysicalRecords;
129}
130
131size_t GOFFOstream::getRemainingSize() {
132 return size_t(&Buffer[BufferSize] - BufferPtr);
133}
134
135void GOFFOstream::write(const char *Ptr, size_t Size) {
136 size_t RemainingSize = getRemainingSize();
137
138 // Data fits into the buffer.
139 if (LLVM_LIKELY(Size <= RemainingSize)) {
140 memcpy(BufferPtr, Ptr, Size);
141 BufferPtr += Size;
142 return;
143 }
144
145 // Otherwise the buffer is partially filled or full, and data does not fit
146 // into it.
147 updateFlagsAndWritePrefix(/*IsContinued=*/true);
148 OS.write(Buffer, size_t(BufferPtr - Buffer));
149 if (RemainingSize > 0) {
150 OS.write(Ptr, RemainingSize);
151 Ptr += RemainingSize;
152 Size -= RemainingSize;
153 }
154
155 while (Size > BufferSize) {
156 updateFlagsAndWritePrefix(/*IsContinued=*/true);
157 OS.write(Ptr, BufferSize);
158 Ptr += BufferSize;
159 Size -= BufferSize;
160 }
161
162 // The remaining bytes fit into the buffer.
163 memcpy(Buffer, Ptr, Size);
164 BufferPtr = &Buffer[Size];
165}
166
167void GOFFOstream::write_zeros(unsigned NumZeros) {
168 assert(NumZeros <= 16 && "Range for zeros too large");
169
170 // Handle the common case first: all fits in the buffer.
171 size_t RemainingSize = getRemainingSize();
172 if (LLVM_LIKELY(RemainingSize >= NumZeros)) {
173 memset(BufferPtr, 0, NumZeros);
174 BufferPtr += NumZeros;
175 return;
176 }
177
178 // Otherwise some field value is cleared.
179 static char Zeros[16] = {
180 0,
181 };
182 write(Zeros, NumZeros);
183}
184
185void GOFFOstream::newRecord(GOFF::RecordType Type) {
186 finalizeRecord();
187 TypeAndFlags = Type << 4;
188 ++LogicalRecords;
189}
190
191void GOFFOstream::finalizeRecord() {
192 if (Buffer == BufferPtr)
193 return;
194 updateFlagsAndWritePrefix(/*IsContinued=*/false);
195 OS.write(Buffer, size_t(BufferPtr - Buffer));
196 OS.write_zeros(getRemainingSize());
197 BufferPtr = Buffer;
198}
199
200namespace {
201// A GOFFSymbol holds all the data required for writing an ESD record.
202class GOFFSymbol {
203public:
204 std::string Name;
205 uint32_t EsdId;
206 uint32_t ParentEsdId;
207 uint64_t Offset = 0; // Offset of the symbol into the section. LD only.
208 // Offset is only 32 bit, the larger type is used to
209 // enable error checking.
212
213 GOFF::BehavioralAttributes BehavAttrs;
214 GOFF::SymbolFlags SymbolFlags;
215 uint32_t SortKey = 0;
216 uint32_t SectionLength = 0;
217 uint32_t ADAEsdId = 0;
218 uint32_t EASectionEDEsdId = 0;
219 uint32_t EASectionOffset = 0;
220 uint8_t FillByteValue = 0;
221
222 GOFFSymbol() : EsdId(0), ParentEsdId(0) {}
223
224 GOFFSymbol(StringRef Name, uint32_t EsdID, const GOFF::SDAttr &Attr)
225 : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(0),
227 BehavAttrs.setTaskingBehavior(Attr.TaskingBehavior);
228 BehavAttrs.setBindingScope(Attr.BindingScope);
229 }
230
231 GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID,
232 const GOFF::EDAttr &Attr, GOFF::ESDAlignment Alignment)
233 : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID),
235 this->NameSpace = Attr.NameSpace;
236 // We always set a fill byte value.
237 this->FillByteValue = Attr.FillByteValue;
238 SymbolFlags.setFillBytePresence(1);
239 SymbolFlags.setReservedQwords(Attr.ReservedQwords);
240 // TODO Do we need/should set the "mangled" flag?
241 BehavAttrs.setReadOnly(Attr.IsReadOnly);
242 BehavAttrs.setRmode(Attr.Rmode);
243 BehavAttrs.setTextStyle(Attr.TextStyle);
244 BehavAttrs.setBindingAlgorithm(Attr.BindAlgorithm);
245 BehavAttrs.setLoadingBehavior(Attr.LoadBehavior);
246 BehavAttrs.setAlignment(Alignment);
247 }
248
249 GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID,
250 GOFF::ESDNameSpaceId NameSpace, const GOFF::LDAttr &Attr)
251 : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID),
252 SymbolType(GOFF::ESD_ST_LabelDefinition), NameSpace(NameSpace) {
253 SymbolFlags.setRenameable(Attr.IsRenameable);
254 BehavAttrs.setExecutable(Attr.Executable);
255 BehavAttrs.setBindingStrength(Attr.BindingStrength);
256 BehavAttrs.setLinkageType(Attr.Linkage);
257 BehavAttrs.setAmode(Attr.Amode);
258 BehavAttrs.setBindingScope(Attr.BindingScope);
259 }
260
261 GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID,
262 const GOFF::EDAttr &EDAttr, GOFF::ESDAlignment Alignment,
263 const GOFF::PRAttr &Attr)
264 : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID),
265 SymbolType(GOFF::ESD_ST_PartReference), NameSpace(EDAttr.NameSpace) {
266 SymbolFlags.setRenameable(Attr.IsRenameable);
267 BehavAttrs.setExecutable(Attr.Executable);
268 BehavAttrs.setBindingStrength(Attr.BindingStrength);
269 BehavAttrs.setLinkageType(Attr.Linkage);
270 // See
271 // https://www.ibm.com/docs/en/hla-and-tf/1.6.0?topic=statements-amode-instruction#amode__modcomb,
272 // Table 2. HLASM sets the AMODE based on the RMODE if no AMODE is given.
273 GOFF::ESDAmode Amode;
274 switch (EDAttr.Rmode) {
275 case GOFF::ESD_RMODE_24:
276 Amode = GOFF::ESD_AMODE_24;
277 break;
278 case GOFF::ESD_RMODE_31:
279 Amode = GOFF::ESD_AMODE_31;
280 break;
281 case GOFF::ESD_RMODE_64:
282 Amode = GOFF::ESD_AMODE_64;
283 break;
284 default:
285 Amode = GOFF::ESD_AMODE_None;
286 break;
287 }
288 BehavAttrs.setAmode(Amode);
289 BehavAttrs.setBindingScope(Attr.BindingScope);
290 BehavAttrs.setAlignment(Alignment);
291 }
292
293 GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID,
294 const GOFF::ERAttr &Attr)
295 : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID),
297 NameSpace(GOFF::ESD_NS_NormalName) {
298 SymbolFlags.setRenameable(Attr.IsRenameable);
299 BehavAttrs.setExecutable(Attr.Executable);
300 BehavAttrs.setBindingStrength(Attr.BindingStrength);
301 BehavAttrs.setLinkageType(Attr.Linkage);
302 BehavAttrs.setAmode(Attr.Amode);
303 BehavAttrs.setBindingScope(Attr.BindingScope);
304 BehavAttrs.setIndirectReference(Attr.IsIndirectReference);
305 }
306};
307
308class GOFFWriter {
309 GOFFOstream OS;
310 MCAssembler &Asm;
311 MCSectionGOFF *RootSD;
312
313 /// Saved relocation data collected in recordRelocations().
314 std::vector<GOFFRelocationEntry> &Relocations;
315
316public:
317 enum DwoMode {
318 AllSections,
319 NonDwoOnly,
320 DwoOnly,
321 };
322
323private:
324 const DwoMode Mode;
325
326 void writeHeader();
327 void writeSymbol(const GOFFSymbol &Symbol);
328 void writeText(const MCSectionGOFF *MC);
329 void writeRelocations();
330 void writeEnd();
331
332 void defineSectionSymbols(const MCSectionGOFF &Section);
333 void defineLabel(const MCSymbolGOFF &Symbol);
334 void defineExtern(const MCSymbolGOFF &Symbol);
335 void defineSymbols();
336
337public:
338 GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm, MCSectionGOFF *RootSD,
339 std::vector<GOFFRelocationEntry> &Relocations, DwoMode Mode);
340 uint64_t writeObject();
341};
342} // namespace
343
344GOFFWriter::GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm,
345 MCSectionGOFF *RootSD,
346 std::vector<GOFFRelocationEntry> &Relocations,
347 DwoMode Mode)
348 : OS(OS), Asm(Asm), RootSD(RootSD), Relocations(Relocations), Mode(Mode) {}
349
350namespace {
351bool isDwoSection(const MCSection &Section) {
352 StringRef Name = Section.getName();
353 return (Name.ends_with(".dwo") && Name.starts_with(".debug_")) ||
354 (Name.ends_with("_DWO") && Name.starts_with("D_"));
355}
356
357bool isSectionToSkip(const MCSection &Section, GOFFWriter::DwoMode Mode) {
358 if (Mode == GOFFWriter::DwoOnly) {
359 if (!isDwoSection(Section))
360 return true;
361 } else if (Mode == GOFFWriter::NonDwoOnly) {
362 if (isDwoSection(Section))
363 return true;
364 }
365 return false;
366}
367} // namespace
368
369void GOFFWriter::defineSectionSymbols(const MCSectionGOFF &Section) {
370 if (isSectionToSkip(Section, Mode))
371 return;
372
373 if (Section.isSD()) {
374 GOFFSymbol SD(Section.getExternalName(), Section.getOrdinal(),
375 Section.getSDAttributes());
376 writeSymbol(SD);
377 }
378
379 if (Section.isED()) {
380 GOFFSymbol ED(Section.getExternalName(), Section.getOrdinal(),
381 Section.getParent()->getOrdinal(), Section.getEDAttributes(),
382 Section.getEDAlignment());
383 ED.SectionLength = Asm.getSectionAddressSize(Section);
384 writeSymbol(ED);
385 }
386
387 if (Section.isPR()) {
388 MCSectionGOFF *Parent = Section.getParent();
389 GOFFSymbol PR(Section.getExternalName(), Section.getOrdinal(),
390 Parent->getOrdinal(), Parent->getEDAttributes(),
391 Parent->getEDAlignment(), Section.getPRAttributes());
392 PR.SectionLength = Asm.getSectionAddressSize(Section);
393 if (Section.requiresNonZeroLength()) {
394 // We cannot have a zero-length section for data. If we do,
395 // artificially inflate it. Use 2 bytes to avoid odd alignments. Note:
396 // if this is ever changed, you will need to update the code in
397 // SystemZAsmPrinter::emitCEEMAIN and SystemZAsmPrinter::emitCELQMAIN to
398 // generate -1 if there is no ADA
399 if (!PR.SectionLength)
400 PR.SectionLength = 2;
401 }
402 writeSymbol(PR);
403 }
404}
405
406void GOFFWriter::defineLabel(const MCSymbolGOFF &Symbol) {
407 MCSectionGOFF &Section = static_cast<MCSectionGOFF &>(Symbol.getSection());
408 GOFFSymbol LD(Symbol.getExternalName(), Symbol.getIndex(),
409 Section.getOrdinal(), Section.getEDAttributes().NameSpace,
410 GOFF::LDAttr{Symbol.isRenameable(), Symbol.getCodeData(),
411 Symbol.getBindingStrength(), Symbol.getLinkage(),
412 GOFF::ESD_AMODE_64, Symbol.getBindingScope()});
413 if (Symbol.getADA())
414 LD.ADAEsdId = Symbol.getADA()->getOrdinal();
415 LD.Offset = Asm.getSymbolOffset(Symbol);
416 writeSymbol(LD);
417}
418
419void GOFFWriter::defineExtern(const MCSymbolGOFF &Symbol) {
420 if (Symbol.getCodeData() == GOFF::ESD_EXE_DATA) {
421 MCSectionGOFF *ED = Symbol.getADA()->getParent();
422 GOFFSymbol PR(Symbol.getExternalName(), Symbol.getIndex(), ED->getOrdinal(),
423 ED->getEDAttributes(), ED->getEDAlignment(),
424 GOFF::PRAttr{Symbol.isRenameable(), Symbol.getCodeData(),
425 Symbol.getBindingStrength(), Symbol.getLinkage(),
426 Symbol.getBindingScope(), 0});
427 writeSymbol(PR);
428 } else {
429 GOFFSymbol ER(Symbol.getExternalName(), Symbol.getIndex(),
430 RootSD->getOrdinal(),
431 GOFF::ERAttr{Symbol.isRenameable(), Symbol.isIndirect(),
432 Symbol.getCodeData(),
433 Symbol.getBindingStrength(), Symbol.getLinkage(),
434 GOFF::ESD_AMODE_64, Symbol.getBindingScope()});
435 writeSymbol(ER);
436 }
437}
438
439void GOFFWriter::defineSymbols() {
440 unsigned Ordinal = 0;
441 // Process all sections.
442 for (MCSection &S : Asm) {
443 auto &Section = static_cast<MCSectionGOFF &>(S);
444 Section.setOrdinal(++Ordinal);
445 defineSectionSymbols(Section);
446 }
447
448 // Process all symbols
449 for (const MCSymbol &Sym : Asm.symbols()) {
450 if (Sym.isTemporary())
451 continue;
452 auto &Symbol = static_cast<const MCSymbolGOFF &>(Sym);
453 if (!Symbol.isDefined()) {
454 if (Mode != DwoOnly) {
455 Symbol.setIndex(++Ordinal);
456 defineExtern(Symbol);
457 }
458 } else {
459 if (isSectionToSkip(Symbol.getSection(), Mode))
460 continue;
461 if (Symbol.isInEDSection()) {
462 Symbol.setIndex(++Ordinal);
463 defineLabel(Symbol);
464 } else {
465 // Symbol is in PR section, the symbol refers to the section.
466 Symbol.setIndex(Symbol.getSection().getOrdinal());
467 }
468 }
469 }
470}
471
472void GOFFWriter::writeHeader() {
473 OS.newRecord(GOFF::RT_HDR);
474 OS.write_zeros(1); // Reserved
475 OS.writebe<uint32_t>(0); // Target Hardware Environment
476 OS.writebe<uint32_t>(0); // Target Operating System Environment
477 OS.write_zeros(2); // Reserved
478 OS.writebe<uint16_t>(0); // CCSID
479 OS.write_zeros(16); // Character Set name
480 OS.write_zeros(16); // Language Product Identifier
481 OS.writebe<uint32_t>(1); // Architecture Level
482 OS.writebe<uint16_t>(0); // Module Properties Length
483 OS.write_zeros(6); // Reserved
484}
485
486void GOFFWriter::writeSymbol(const GOFFSymbol &Symbol) {
487 if (Symbol.Offset >= (((uint64_t)1) << 31))
488 report_fatal_error("ESD offset out of range");
489
490 // All symbol names are in EBCDIC.
491 SmallString<256> Name;
493
494 // Check length here since this number is technically signed but we need uint
495 // for writing to records.
496 if (Name.size() >= GOFF::MaxDataLength)
497 report_fatal_error("Symbol max name length exceeded");
498 uint16_t NameLength = Name.size();
499
500 OS.newRecord(GOFF::RT_ESD);
501 OS.writebe<uint8_t>(Symbol.SymbolType); // Symbol Type
502 OS.writebe<uint32_t>(Symbol.EsdId); // ESDID
503 OS.writebe<uint32_t>(Symbol.ParentEsdId); // Parent or Owning ESDID
504 OS.writebe<uint32_t>(0); // Reserved
505 OS.writebe<uint32_t>(
506 static_cast<uint32_t>(Symbol.Offset)); // Offset or Address
507 OS.writebe<uint32_t>(0); // Reserved
508 OS.writebe<uint32_t>(Symbol.SectionLength); // Length
509 OS.writebe<uint32_t>(Symbol.EASectionEDEsdId); // Extended Attribute ESDID
510 OS.writebe<uint32_t>(Symbol.EASectionOffset); // Extended Attribute Offset
511 OS.writebe<uint32_t>(0); // Reserved
512 OS.writebe<uint8_t>(Symbol.NameSpace); // Name Space ID
513 OS.writebe<uint8_t>(Symbol.SymbolFlags); // Flags
514 OS.writebe<uint8_t>(Symbol.FillByteValue); // Fill-Byte Value
515 OS.writebe<uint8_t>(0); // Reserved
516 OS.writebe<uint32_t>(Symbol.ADAEsdId); // ADA ESDID
517 OS.writebe<uint32_t>(Symbol.SortKey); // Sort Priority
518 OS.writebe<uint64_t>(0); // Reserved
519 for (auto F : Symbol.BehavAttrs.Attr)
520 OS.writebe<uint8_t>(F); // Behavioral Attributes
521 OS.writebe<uint16_t>(NameLength); // Name Length
522 OS.write(Name.data(), NameLength); // Name
523}
524
525namespace {
526/// Adapter stream to write a text section.
527class TextStream : public raw_ostream {
528 /// The underlying GOFFOstream.
529 GOFFOstream &OS;
530
531 /// The buffer size is the maximum number of bytes in a TXT section.
532 static constexpr size_t BufferSize = GOFF::MaxDataLength;
533
534 /// Static allocated buffer for the stream, used by the raw_ostream class. The
535 /// buffer is sized to hold the payload of a logical TXT record.
536 char Buffer[BufferSize];
537
538 /// The offset for the next TXT record. This is equal to the number of bytes
539 /// written.
540 size_t Offset;
541
542 /// The Esdid of the GOFF section.
543 const uint32_t EsdId;
544
545 /// The record style.
546 const GOFF::ESDTextStyle RecordStyle;
547
548 /// See raw_ostream::write_impl.
549 void write_impl(const char *Ptr, size_t Size) override;
550
551 uint64_t current_pos() const override { return Offset; }
552
553public:
554 explicit TextStream(GOFFOstream &OS, uint32_t EsdId,
555 GOFF::ESDTextStyle RecordStyle)
556 : OS(OS), Offset(0), EsdId(EsdId), RecordStyle(RecordStyle) {
557 SetBuffer(Buffer, sizeof(Buffer));
558 }
559
560 ~TextStream() override { flush(); }
561};
562} // namespace
563
564void TextStream::write_impl(const char *Ptr, size_t Size) {
565 size_t WrittenLength = 0;
566
567 // We only have signed 32bits of offset.
568 if (Offset + Size > std::numeric_limits<int32_t>::max())
569 report_fatal_error("TXT section too large");
570
571 while (WrittenLength < Size) {
572 size_t ToWriteLength =
573 std::min(Size - WrittenLength, size_t(GOFF::MaxDataLength));
574
575 OS.newRecord(GOFF::RT_TXT);
576 OS.writebe<uint8_t>(GOFF::Flags(4, 4, RecordStyle)); // Text Record Style
577 OS.writebe<uint32_t>(EsdId); // Element ESDID
578 OS.writebe<uint32_t>(0); // Reserved
579 OS.writebe<uint32_t>(static_cast<uint32_t>(Offset)); // Offset
580 OS.writebe<uint32_t>(0); // Text Field True Length
581 OS.writebe<uint16_t>(0); // Text Encoding
582 OS.writebe<uint16_t>(ToWriteLength); // Data Length
583 OS.write(Ptr + WrittenLength, ToWriteLength); // Data
584
585 WrittenLength += ToWriteLength;
586 Offset += ToWriteLength;
587 }
588}
589
590void GOFFWriter::writeText(const MCSectionGOFF *Section) {
591 // A BSS section contains only zeros, no need to write this.
592 if (Section->isBSS())
593 return;
594
595 TextStream S(OS, Section->getOrdinal(), Section->getTextStyle());
596 Asm.writeSectionData(S, Section);
597}
598
599namespace {
600// RelocDataItemBuffer provides a static buffer for relocation data items.
601class RelocDataItemBuffer {
602 char Buffer[GOFF::MaxDataLength];
603 char *Ptr;
604
605public:
606 RelocDataItemBuffer() : Ptr(Buffer) {}
607 const char *data() { return Buffer; }
608 size_t size() { return Ptr - Buffer; }
609 void reset() { Ptr = Buffer; }
610 bool fits(size_t S) { return size() + S < GOFF::MaxDataLength; }
611 template <typename T> void writebe(T Val) {
612 assert(fits(sizeof(T)) && "Out-of-bounds write");
614 Ptr += sizeof(T);
615 }
616};
617} // namespace
618
619void GOFFWriter::writeRelocations() {
620 // Set the IDs in the relocation entries.
621 for (auto &RelocEntry : Relocations) {
622 auto GetRptr = [](const MCSymbolGOFF *Sym) -> uint32_t {
623 if (Sym->isTemporary())
624 return static_cast<MCSectionGOFF &>(Sym->getSection()).getOrdinal();
625 return Sym->getIndex();
626 };
627
628 RelocEntry.PEsdId = RelocEntry.Pptr->getOrdinal();
629 RelocEntry.REsdId = GetRptr(RelocEntry.Rptr);
630 }
631
632 // Sort relocation data items by the P pointer to save space.
633 std::sort(
634 Relocations.begin(), Relocations.end(),
635 [](const GOFFRelocationEntry &Left, const GOFFRelocationEntry &Right) {
636 return std::tie(Left.PEsdId, Left.REsdId, Left.POffset) <
637 std::tie(Right.PEsdId, Right.REsdId, Right.POffset);
638 });
639
640 // Construct the compressed relocation data items, and write them out.
641 RelocDataItemBuffer Buffer;
642 for (auto I = Relocations.begin(), E = Relocations.end(); I != E;) {
643 Buffer.reset();
644
645 uint32_t PrevResdId = -1;
646 uint32_t PrevPesdId = -1;
647 uint64_t PrevPOffset = -1;
648 for (; I != E; ++I) {
649 const GOFFRelocationEntry &Rel = *I;
650
651 bool SameREsdId = (Rel.REsdId == PrevResdId);
652 bool SamePEsdId = (Rel.PEsdId == PrevPesdId);
653 bool SamePOffset = (Rel.POffset == PrevPOffset);
654 bool EightByteOffset = ((Rel.POffset >> 32) & 0xffffffff);
655
656 // Calculate size of relocation data item, and check if it still fits into
657 // the record.
658 size_t ItemSize = 8; // Smallest size of a relocation data item.
659 if (!SameREsdId)
660 ItemSize += 4;
661 if (!SamePEsdId)
662 ItemSize += 4;
663 if (!SamePOffset)
664 ItemSize += (EightByteOffset ? 8 : 4);
665 if (!Buffer.fits(ItemSize))
666 break;
667
668 GOFF::Flags RelocFlags[6];
669 RelocFlags[0].set(0, 1, SameREsdId);
670 RelocFlags[0].set(1, 1, SamePEsdId);
671 RelocFlags[0].set(2, 1, SamePOffset);
672 RelocFlags[0].set(6, 1, EightByteOffset);
673
674 RelocFlags[1].set(0, 4, Rel.ReferenceType);
675 RelocFlags[1].set(4, 4, Rel.ReferentType);
676
677 RelocFlags[2].set(0, 7, Rel.Action);
678 RelocFlags[2].set(7, 1, Rel.FetchStore);
679
680 RelocFlags[4].set(0, 8, Rel.TargetLength);
681
682 for (auto F : RelocFlags)
683 Buffer.writebe<uint8_t>(F);
684 Buffer.writebe<uint16_t>(0); // Reserved.
685 if (!SameREsdId)
686 Buffer.writebe<uint32_t>(Rel.REsdId);
687 if (!SamePEsdId)
688 Buffer.writebe<uint32_t>(Rel.PEsdId);
689 if (!SamePOffset) {
690 if (EightByteOffset)
691 Buffer.writebe<uint64_t>(Rel.POffset);
692 else
693 Buffer.writebe<uint32_t>(Rel.POffset);
694 }
695
696 PrevResdId = Rel.REsdId;
697 PrevPesdId = Rel.PEsdId;
698 PrevPOffset = Rel.POffset;
699 }
700
701 OS.newRecord(GOFF::RT_RLD);
702 OS.writebe<uint8_t>(0); // Reserved.
703 OS.writebe<uint16_t>(Buffer.size()); // Length (of the relocation data).
704 OS.write(Buffer.data(), Buffer.size()); // Relocation Directory Data Items.
705 }
706}
707
708void GOFFWriter::writeEnd() {
709 uint8_t F = GOFF::END_EPR_None;
710 uint8_t AMODE = 0;
711 uint32_t ESDID = 0;
712
713 // TODO Set Flags/AMODE/ESDID for entry point.
714
715 OS.newRecord(GOFF::RT_END);
716 OS.writebe<uint8_t>(GOFF::Flags(6, 2, F)); // Indicator flags
717 OS.writebe<uint8_t>(AMODE); // AMODE
718 OS.write_zeros(3); // Reserved
719 // The record count is the number of logical records. In principle, this value
720 // is available as OS.logicalRecords(). However, some tools rely on this field
721 // being zero.
722 OS.writebe<uint32_t>(0); // Record Count
723 OS.writebe<uint32_t>(ESDID); // ESDID (of entry point)
724}
725
726uint64_t GOFFWriter::writeObject() {
727 writeHeader();
728
729 defineSymbols();
730
731 for (const MCSection &Section : Asm)
732 writeText(static_cast<const MCSectionGOFF *>(&Section));
733
734 // Do not write relocations into the dwo file.
735 if (Mode != GOFFWriter::DwoOnly)
736 writeRelocations();
737
738 writeEnd();
739
740 // Make sure all records are written.
741 OS.finalizeRecord();
742
743 LLVM_DEBUG(dbgs() << "Wrote " << OS.getNumLogicalRecords()
744 << " logical records.");
745
746 return OS.getWrittenSize();
747}
748
750 std::unique_ptr<MCGOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS)
751 : TargetObjectWriter(std::move(MOTW)), OS(OS) {}
752
754 std::unique_ptr<MCGOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS,
755 raw_pwrite_stream &DwoOS)
756 : TargetObjectWriter(std::move(MOTW)), OS(OS), DwoOS(&DwoOS) {}
757
759
761 Relocations.clear();
762 RootSD = nullptr;
764}
765
767 const MCFixup &Fixup, MCValue Target,
768 uint64_t &FixedValue) {
769 const MCFixupKindInfo &FKI =
770 Asm->getBackend().getFixupKindInfo(Fixup.getKind());
771 const uint32_t Length = FKI.TargetSize / 8;
772 assert(FKI.TargetSize % 8 == 0 && "Target Size not multiple of 8");
773 const uint64_t FixupOffset = Asm->getFragmentOffset(F) + Fixup.getOffset();
774
775 unsigned RelocType = TargetObjectWriter->getRelocType(Target, Fixup);
776
777 const MCSectionGOFF *PSection = static_cast<MCSectionGOFF *>(F.getParent());
778 const auto &A = *static_cast<const MCSymbolGOFF *>(Target.getAddSym());
779 const MCSymbolGOFF *B = static_cast<const MCSymbolGOFF *>(Target.getSubSym());
781 if (A.isUndefined()) {
782 Asm->reportError(
783 Fixup.getLoc(),
784 Twine("symbol ")
785 .concat(A.getExternalName())
786 .concat(" must be defined for a relative immediate relocation"));
787 return;
788 }
789 if (&A.getSection() != PSection) {
790 MCSectionGOFF &GOFFSection = static_cast<MCSectionGOFF &>(A.getSection());
791 Asm->reportError(Fixup.getLoc(),
792 Twine("relative immediate relocation section mismatch: ")
793 .concat(GOFFSection.getExternalName())
794 .concat(" of symbol ")
795 .concat(A.getExternalName())
796 .concat(" <-> ")
797 .concat(PSection->getExternalName()));
798 return;
799 }
800 if (B) {
801 Asm->reportError(
802 Fixup.getLoc(),
803 Twine("subtractive symbol ")
804 .concat(B->getExternalName())
805 .concat(" not supported for a relative immediate relocation"));
806 return;
807 }
808 FixedValue = Asm->getSymbolOffset(A) - FixupOffset + Target.getConstant();
809 return;
810 }
811 FixedValue = Target.getConstant();
812
813 // The symbol only has a section-relative offset if it is a temporary symbol.
814 FixedValue += A.isTemporary() ? Asm->getSymbolOffset(A) : 0;
815 A.setUsedInReloc();
816 if (B) {
817 FixedValue -= B->isTemporary() ? Asm->getSymbolOffset(*B) : 0;
818 B->setUsedInReloc();
819 }
820
821 // The z/OS binder requires all ADCONs in C_WSA64 to be exactly 8 bytes; a
822 // sub-pointer-width address constant in the writable static area cannot be
823 // relocated by the binder (it would produce IEW2572E at bind time).
826 Length != 8 && PSection->getParent() &&
827 PSection->getParent()->getName() == GOFF::CLASS_WSA) {
828 Asm->reportError(Fixup.getLoc(),
829 "address constant in C_WSA64 must be 8 bytes "
830 "(z/OS binder restriction IEW2572E)");
831 return;
832 }
833
834 // UseQCon causes class offsets versus absolute addresses to be used. This
835 // is analogous to using QCONs in older OBJ object file format.
836 bool UseQCon = RelocType == MCGOFFObjectTargetWriter::Reloc_Type_QCon;
837
838 GOFF::RLDFetchStore FetchStore =
843 assert((FetchStore == GOFF::RLDFetchStore::RLD_FS_Fetch || B == nullptr) &&
844 "No dependent relocations expected");
845
847 enum GOFF::RLDReferentType ReferentType = GOFF::RLD_RO_Label;
848 if (UseQCon) {
850 ReferentType = GOFF::RLD_RO_Class;
851 }
854
855 auto DumpReloc = [&PSection, &ReferenceType, &FixupOffset,
856 &FixedValue](const char *N, const MCSymbolGOFF *Sym) {
857 const char *Con;
858 switch (ReferenceType) {
860 Con = "ACon";
861 break;
863 Con = "QCon";
864 break;
866 Con = "VCon";
867 break;
868 default:
869 Con = "(unknown)";
870 }
871 dbgs() << "Reloc " << N << ": " << Con
872 << " Rptr: " << Sym->getExternalName()
873 << " Pptr: " << PSection->getExternalName()
874 << " Offset: " << FixupOffset << " Fixed Imm: " << FixedValue
875 << "\n";
876 };
877 (void)DumpReloc;
878
879 // Save relocation data for later writing.
880 LLVM_DEBUG(DumpReloc("A", &A));
881 Relocations.emplace_back(PSection, &A, ReferenceType, ReferentType,
882 GOFF::RLD_ACT_Add, FetchStore, FixupOffset, Length);
883 if (B) {
884 LLVM_DEBUG(DumpReloc("B", B));
885 Relocations.emplace_back(
886 PSection, B, ReferenceType, ReferentType, GOFF::RLD_ACT_Subtract,
888 }
889}
890
892 uint64_t Size = 0;
893 if (DwoOS)
894 Size += GOFFWriter(*DwoOS, *Asm, RootSD, Relocations, GOFFWriter::DwoOnly)
895 .writeObject();
896 Size += GOFFWriter(OS, *Asm, RootSD, Relocations,
897 DwoOS ? GOFFWriter::NonDwoOnly : GOFFWriter::AllSections)
898 .writeObject();
899 return Size;
900}
901
902std::unique_ptr<MCObjectWriter>
903llvm::createGOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW,
904 raw_pwrite_stream &OS) {
905 return std::make_unique<GOFFObjectWriter>(std::move(MOTW), OS);
906}
907
908std::unique_ptr<MCObjectWriter>
909llvm::createGOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW,
911 return std::make_unique<GOFFObjectWriter>(std::move(MOTW), OS, DwoOS);
912}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_LIKELY(EXPR)
Definition Compiler.h:347
This file provides utility functions for converting between EBCDIC-1047 and UTF-8.
This file declares the MCSectionGOFF class, which contains all of the necessary machine code sections...
This file contains the MCSymbolGOFF class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define T
static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))
static Split data
#define LLVM_DEBUG(...)
Definition Debug.h:119
static bool isDwoSection(const MCSection &Sec)
GOFFObjectWriter(std::unique_ptr< MCGOFFObjectTargetWriter > MOTW, raw_pwrite_stream &OS)
void reset() override
lifetime management
uint64_t writeObject() override
Write the object file and returns the number of bytes written.
~GOFFObjectWriter() override
void recordRelocation(const MCFragment &F, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) override
Record a relocation entry.
constexpr void set(uint8_t BitIndex, uint8_t Length, T NewValue)
Definition GOFF.h:210
LLVM_ABI bool getSymbolOffset(const MCSymbol &S, uint64_t &Val) const
LLVM_ABI uint64_t getSectionAddressSize(const MCSection &Sec) const
Encode information on a single operation to perform on a byte sequence (e.g., an encoded instruction)...
Definition MCFixup.h:65
virtual void reset()
lifetime management
GOFF::EDAttr getEDAttributes() const
StringRef getExternalName() const
GOFF::ESDAlignment getEDAlignment() const
MCSectionGOFF * getParent() const
Instances of this class represent a uniqued identifier for a section in the current translation unit.
Definition MCSection.h:580
unsigned getOrdinal() const
Definition MCSection.h:673
StringRef getName() const
Definition MCSection.h:650
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
Target - Wrapper for Target specific information.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
Twine concat(const Twine &Suffix) const
Definition Twine.h:497
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM Value Representation.
Definition Value.h:75
raw_ostream & write_zeros(unsigned NumZeros)
write_zeros - Insert 'NumZeros' nulls.
raw_ostream & write(unsigned char C)
An abstract base class for streams implementations that also support a pwrite operation.
LLVM_ABI std::error_code convertToEBCDIC(StringRef Source, SmallVectorImpl< char > &Result)
Converts UTF-8 text containing only code points in the range U+0000 to U+00FF to EBCDIC-1047.
LLVM_ABI void writeHeader(support::endian::Writer &W, bool Is64Bit, uint8_t OSABI, uint8_t ABIVersion, uint16_t EMachine, uint32_t EFlags, uint64_t SHOff, uint16_t SHNum, uint16_t SHStrNdx)
Write an ELF file header (Elf32_Ehdr or Elf64_Ehdr) for an ET_REL object.
Definition ELFWriter.cpp:21
RecordType
Definition GOFF.h:44
@ RT_RLD
Definition GOFF.h:47
@ RT_TXT
Definition GOFF.h:46
@ RT_ESD
Definition GOFF.h:45
@ RT_HDR
Definition GOFF.h:50
@ RT_END
Definition GOFF.h:49
constexpr StringLiteral CLASS_WSA
@ RLD_ACT_Subtract
Definition GOFF.h:178
@ RLD_ACT_Add
Definition GOFF.h:177
RLDFetchStore
Definition GOFF.h:181
@ RLD_FS_Store
Definition GOFF.h:181
@ RLD_FS_Fetch
Definition GOFF.h:181
constexpr uint8_t PayloadLength
Definition GOFF.h:30
ESDTextStyle
Definition GOFF.h:91
@ ESD_EXE_DATA
Definition GOFF.h:111
constexpr uint16_t MaxDataLength
Maximum data length before starting a new card for RLD and TXT data.
Definition GOFF.h:39
@ END_EPR_None
Definition GOFF.h:184
ESDAlignment
Definition GOFF.h:144
RLDReferenceType
Definition GOFF.h:160
@ RLD_RT_RAddress
Definition GOFF.h:161
@ RLD_RT_ROffset
Definition GOFF.h:162
@ RLD_RT_RTypeConstant
Definition GOFF.h:165
RLDReferentType
Definition GOFF.h:169
@ RLD_RO_Label
Definition GOFF.h:170
@ RLD_RO_Class
Definition GOFF.h:172
constexpr uint8_t PTVPrefix
Prefix byte on every record. This indicates GOFF format.
Definition GOFF.h:42
constexpr uint8_t RecordLength
Length of the parts of a physical GOFF record.
Definition GOFF.h:28
ESDNameSpaceId
Definition GOFF.h:61
@ ESD_NS_ProgramManagementBinder
Definition GOFF.h:62
@ ESD_NS_NormalName
Definition GOFF.h:63
ESDSymbolType
Definition GOFF.h:53
@ ESD_ST_PartReference
Definition GOFF.h:57
@ ESD_ST_ElementDefinition
Definition GOFF.h:55
@ ESD_ST_LabelDefinition
Definition GOFF.h:56
@ ESD_ST_SectionDefinition
Definition GOFF.h:54
@ ESD_ST_ExternalReference
Definition GOFF.h:58
SymbolFlags
Symbol flags.
Definition Symbol.h:25
value_type byte_swap(value_type value, endianness endian)
Swap the bytes of value to match the given endianness.
Definition Endian.h:45
void write(void *memory, value_type value, endianness endian)
Write a value to memory with a particular endianness.
Definition Endian.h:82
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
@ Length
Definition DWP.cpp:577
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1685
LLVM_ABI std::unique_ptr< MCObjectWriter > createGOFFObjectWriter(std::unique_ptr< MCGOFFObjectTargetWriter > MOTW, raw_pwrite_stream &OS)
Construct a new GOFF writer instance.
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&...Ranges)
Returns a concatenated range across two or more ranges.
Definition STLExtras.h:1167
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1933
LLVM_ABI Error write(DWPWriter &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue, Dwarf64StrOffsetsPromotion StrOffsetsOptValue, raw_pwrite_stream *OS=nullptr)
Definition DWP.cpp:746
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:879
#define N
GOFF::RLDReferenceType ReferenceType
GOFF::RLDFetchStore FetchStore
GOFF::RLDReferentType ReferentType
GOFF::ESDReserveQwords ReservedQwords
GOFF::ESDRmode Rmode
GOFF::ESDTextStyle TextStyle
GOFF::ESDLoadingBehavior LoadBehavior
GOFF::ESDNameSpaceId NameSpace
GOFF::ESDBindingAlgorithm BindAlgorithm
GOFF::ESDBindingScope BindingScope
GOFF::ESDBindingStrength BindingStrength
GOFF::ESDLinkageType Linkage
GOFF::ESDExecutable Executable
GOFF::ESDAmode Amode
GOFF::ESDAmode Amode
GOFF::ESDBindingStrength BindingStrength
GOFF::ESDExecutable Executable
GOFF::ESDBindingScope BindingScope
GOFF::ESDLinkageType Linkage
GOFF::ESDLinkageType Linkage
GOFF::ESDBindingStrength BindingStrength
GOFF::ESDBindingScope BindingScope
GOFF::ESDExecutable Executable
GOFF::ESDTaskingBehavior TaskingBehavior
GOFF::ESDBindingScope BindingScope
Target independent information on a fixup kind.
uint8_t TargetSize
The number of bits written by this fixup.