LLVM 22.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"
20#include "llvm/MC/MCValue.h"
22#include "llvm/Support/Debug.h"
23#include "llvm/Support/Endian.h"
25
26using namespace llvm;
27
28#define DEBUG_TYPE "goff-writer"
29
30namespace {
31// Common flag values on records.
32
33// Flag: This record is continued.
34constexpr uint8_t RecContinued = GOFF::Flags(7, 1, 1);
35
36// Flag: This record is a continuation.
37constexpr uint8_t RecContinuation = GOFF::Flags(6, 1, 1);
38
39// The GOFFOstream is responsible to write the data into the fixed physical
40// records of the format. A user of this class announces the begin of a new
41// logical record. While writing the payload, the physical records are created
42// for the data. Possible fill bytes at the end of a physical record are written
43// automatically. In principle, the GOFFOstream is agnostic of the endianness of
44// the payload. However, it also supports writing data in big endian byte order.
45//
46// The physical records use the flag field to indicate if the there is a
47// successor and predecessor record. To be able to set these flags while
48// writing, the basic implementation idea is to always buffer the last seen
49// physical record.
50class GOFFOstream {
51 /// The underlying raw_pwrite_stream.
53
54 /// The number of logical records emitted so far.
55 uint32_t LogicalRecords = 0;
56
57 /// The number of physical records emitted so far.
58 uint32_t PhysicalRecords = 0;
59
60 /// The size of the buffer. Same as the payload size of a physical record.
61 static constexpr uint8_t BufferSize = GOFF::PayloadLength;
62
63 /// Current position in buffer.
64 char *BufferPtr = Buffer;
65
66 /// Static allocated buffer for the stream.
67 char Buffer[BufferSize];
68
69 /// The type of the current logical record, and the flags (aka continued and
70 /// continuation indicators) for the previous (physical) record.
71 uint8_t TypeAndFlags = 0;
72
73public:
74 GOFFOstream(raw_pwrite_stream &OS);
75 ~GOFFOstream();
76
77 raw_pwrite_stream &getOS() { return OS; }
78 size_t getWrittenSize() const { return PhysicalRecords * GOFF::RecordLength; }
79 uint32_t getNumLogicalRecords() { return LogicalRecords; }
80
81 /// Write the specified bytes.
82 void write(const char *Ptr, size_t Size);
83
84 /// Write zeroes, up to a maximum of 16 bytes.
85 void write_zeros(unsigned NumZeros);
86
87 /// Support for endian-specific data.
88 template <typename value_type> void writebe(value_type Value) {
89 Value =
91 write((const char *)&Value, sizeof(value_type));
92 }
93
94 /// Begin a new logical record. Implies finalizing the previous record.
95 void newRecord(GOFF::RecordType Type);
96
97 /// Ends a logical record.
98 void finalizeRecord();
99
100private:
101 /// Updates the continued/continuation flags, and writes the record prefix of
102 /// a physical record.
103 void updateFlagsAndWritePrefix(bool IsContinued);
104
105 /// Returns the remaining size in the buffer.
106 size_t getRemainingSize();
107};
108} // namespace
109
110GOFFOstream::GOFFOstream(raw_pwrite_stream &OS) : OS(OS) {}
111
112GOFFOstream::~GOFFOstream() { finalizeRecord(); }
113
114void GOFFOstream::updateFlagsAndWritePrefix(bool IsContinued) {
115 // Update the flags based on the previous state and the flag IsContinued.
116 if (TypeAndFlags & RecContinued)
117 TypeAndFlags |= RecContinuation;
118 if (IsContinued)
119 TypeAndFlags |= RecContinued;
120 else
121 TypeAndFlags &= ~RecContinued;
122
123 OS << static_cast<unsigned char>(GOFF::PTVPrefix) // Record Type
124 << static_cast<unsigned char>(TypeAndFlags) // Continuation
125 << static_cast<unsigned char>(0); // Version
126
127 ++PhysicalRecords;
128}
129
130size_t GOFFOstream::getRemainingSize() {
131 return size_t(&Buffer[BufferSize] - BufferPtr);
132}
133
134void GOFFOstream::write(const char *Ptr, size_t Size) {
135 size_t RemainingSize = getRemainingSize();
136
137 // Data fits into the buffer.
138 if (LLVM_LIKELY(Size <= RemainingSize)) {
139 memcpy(BufferPtr, Ptr, Size);
140 BufferPtr += Size;
141 return;
142 }
143
144 // Otherwise the buffer is partially filled or full, and data does not fit
145 // into it.
146 updateFlagsAndWritePrefix(/*IsContinued=*/true);
147 OS.write(Buffer, size_t(BufferPtr - Buffer));
148 if (RemainingSize > 0) {
149 OS.write(Ptr, RemainingSize);
150 Ptr += RemainingSize;
151 Size -= RemainingSize;
152 }
153
154 while (Size > BufferSize) {
155 updateFlagsAndWritePrefix(/*IsContinued=*/true);
156 OS.write(Ptr, BufferSize);
157 Ptr += BufferSize;
158 Size -= BufferSize;
159 }
160
161 // The remaining bytes fit into the buffer.
162 memcpy(Buffer, Ptr, Size);
163 BufferPtr = &Buffer[Size];
164}
165
166void GOFFOstream::write_zeros(unsigned NumZeros) {
167 assert(NumZeros <= 16 && "Range for zeros too large");
168
169 // Handle the common case first: all fits in the buffer.
170 size_t RemainingSize = getRemainingSize();
171 if (LLVM_LIKELY(RemainingSize >= NumZeros)) {
172 memset(BufferPtr, 0, NumZeros);
173 BufferPtr += NumZeros;
174 return;
175 }
176
177 // Otherwise some field value is cleared.
178 static char Zeros[16] = {
179 0,
180 };
181 write(Zeros, NumZeros);
182}
183
184void GOFFOstream::newRecord(GOFF::RecordType Type) {
185 finalizeRecord();
186 TypeAndFlags = Type << 4;
187 ++LogicalRecords;
188}
189
190void GOFFOstream::finalizeRecord() {
191 if (Buffer == BufferPtr)
192 return;
193 updateFlagsAndWritePrefix(/*IsContinued=*/false);
194 OS.write(Buffer, size_t(BufferPtr - Buffer));
195 OS.write_zeros(getRemainingSize());
196 BufferPtr = Buffer;
197}
198
199namespace {
200// A GOFFSymbol holds all the data required for writing an ESD record.
201class GOFFSymbol {
202public:
203 std::string Name;
204 uint32_t EsdId;
205 uint32_t ParentEsdId;
206 uint64_t Offset = 0; // Offset of the symbol into the section. LD only.
207 // Offset is only 32 bit, the larger type is used to
208 // enable error checking.
211
212 GOFF::BehavioralAttributes BehavAttrs;
213 GOFF::SymbolFlags SymbolFlags;
214 uint32_t SortKey = 0;
215 uint32_t SectionLength = 0;
216 uint32_t ADAEsdId = 0;
217 uint32_t EASectionEDEsdId = 0;
218 uint32_t EASectionOffset = 0;
219 uint8_t FillByteValue = 0;
220
221 GOFFSymbol() : EsdId(0), ParentEsdId(0) {}
222
223 GOFFSymbol(StringRef Name, uint32_t EsdID, const GOFF::SDAttr &Attr)
224 : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(0),
226 BehavAttrs.setTaskingBehavior(Attr.TaskingBehavior);
227 BehavAttrs.setBindingScope(Attr.BindingScope);
228 }
229
230 GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID,
231 const GOFF::EDAttr &Attr)
232 : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID),
234 this->NameSpace = Attr.NameSpace;
235 // We always set a fill byte value.
236 this->FillByteValue = Attr.FillByteValue;
237 SymbolFlags.setFillBytePresence(1);
238 SymbolFlags.setReservedQwords(Attr.ReservedQwords);
239 // TODO Do we need/should set the "mangled" flag?
240 BehavAttrs.setReadOnly(Attr.IsReadOnly);
241 BehavAttrs.setRmode(Attr.Rmode);
242 BehavAttrs.setTextStyle(Attr.TextStyle);
243 BehavAttrs.setBindingAlgorithm(Attr.BindAlgorithm);
244 BehavAttrs.setLoadingBehavior(Attr.LoadBehavior);
245 BehavAttrs.setAlignment(Attr.Alignment);
246 }
247
248 GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID,
249 GOFF::ESDNameSpaceId NameSpace, const GOFF::LDAttr &Attr)
250 : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID),
251 SymbolType(GOFF::ESD_ST_LabelDefinition), NameSpace(NameSpace) {
252 SymbolFlags.setRenameable(Attr.IsRenamable);
253 BehavAttrs.setExecutable(Attr.Executable);
254 BehavAttrs.setBindingStrength(Attr.BindingStrength);
255 BehavAttrs.setLinkageType(Attr.Linkage);
256 BehavAttrs.setAmode(Attr.Amode);
257 BehavAttrs.setBindingScope(Attr.BindingScope);
258 }
259
260 GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID,
261 const GOFF::EDAttr &EDAttr, const GOFF::PRAttr &Attr)
262 : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID),
263 SymbolType(GOFF::ESD_ST_PartReference), NameSpace(EDAttr.NameSpace) {
264 SymbolFlags.setRenameable(Attr.IsRenamable);
265 BehavAttrs.setExecutable(Attr.Executable);
266 BehavAttrs.setLinkageType(Attr.Linkage);
267 BehavAttrs.setBindingScope(Attr.BindingScope);
268 BehavAttrs.setAlignment(EDAttr.Alignment);
269 }
270
271 GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID,
272 const GOFF::ERAttr &Attr)
273 : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID),
275 NameSpace(GOFF::ESD_NS_NormalName) {
276 BehavAttrs.setExecutable(Attr.Executable);
277 BehavAttrs.setBindingStrength(Attr.BindingStrength);
278 BehavAttrs.setLinkageType(Attr.Linkage);
279 BehavAttrs.setAmode(Attr.Amode);
280 BehavAttrs.setBindingScope(Attr.BindingScope);
281 }
282};
283
284class GOFFWriter {
285 GOFFOstream OS;
286 MCAssembler &Asm;
287 MCSectionGOFF *RootSD;
288
289 /// Saved relocation data collected in recordRelocations().
290 std::vector<GOFFRelocationEntry> &Relocations;
291
292 void writeHeader();
293 void writeSymbol(const GOFFSymbol &Symbol);
294 void writeText(const MCSectionGOFF *MC);
295 void writeRelocations();
296 void writeEnd();
297
298 void defineSectionSymbols(const MCSectionGOFF &Section);
299 void defineLabel(const MCSymbolGOFF &Symbol);
300 void defineExtern(const MCSymbolGOFF &Symbol);
301 void defineSymbols();
302
303public:
304 GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm, MCSectionGOFF *RootSD,
305 std::vector<GOFFRelocationEntry> &Relocations);
306 uint64_t writeObject();
307};
308} // namespace
309
310GOFFWriter::GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm,
311 MCSectionGOFF *RootSD,
312 std::vector<GOFFRelocationEntry> &Relocations)
313 : OS(OS), Asm(Asm), RootSD(RootSD), Relocations(Relocations) {}
314
315void GOFFWriter::defineSectionSymbols(const MCSectionGOFF &Section) {
316 if (Section.isSD()) {
317 GOFFSymbol SD(Section.getName(), Section.getOrdinal(),
318 Section.getSDAttributes());
319 writeSymbol(SD);
320 }
321
322 if (Section.isED()) {
323 GOFFSymbol ED(Section.getName(), Section.getOrdinal(),
324 Section.getParent()->getOrdinal(), Section.getEDAttributes());
325 ED.SectionLength = Asm.getSectionAddressSize(Section);
326 writeSymbol(ED);
327 }
328
329 if (Section.isPR()) {
330 MCSectionGOFF *Parent = Section.getParent();
331 GOFFSymbol PR(Section.getName(), Section.getOrdinal(), Parent->getOrdinal(),
332 Parent->getEDAttributes(), Section.getPRAttributes());
333 PR.SectionLength = Asm.getSectionAddressSize(Section);
334 if (Section.requiresNonZeroLength()) {
335 // We cannot have a zero-length section for data. If we do,
336 // artificially inflate it. Use 2 bytes to avoid odd alignments. Note:
337 // if this is ever changed, you will need to update the code in
338 // SystemZAsmPrinter::emitCEEMAIN and SystemZAsmPrinter::emitCELQMAIN to
339 // generate -1 if there is no ADA
340 if (!PR.SectionLength)
341 PR.SectionLength = 2;
342 }
343 writeSymbol(PR);
344 }
345}
346
347void GOFFWriter::defineLabel(const MCSymbolGOFF &Symbol) {
348 MCSectionGOFF &Section = static_cast<MCSectionGOFF &>(Symbol.getSection());
349 GOFFSymbol LD(Symbol.getName(), Symbol.getIndex(), Section.getOrdinal(),
350 Section.getEDAttributes().NameSpace,
351 GOFF::LDAttr{false, Symbol.getCodeData(),
352 Symbol.getBindingStrength(), Symbol.getLinkage(),
353 GOFF::ESD_AMODE_64, Symbol.getBindingScope()});
354 if (Symbol.getADA())
355 LD.ADAEsdId = Symbol.getADA()->getOrdinal();
356 LD.Offset = Asm.getSymbolOffset(Symbol);
357 writeSymbol(LD);
358}
359
360void GOFFWriter::defineExtern(const MCSymbolGOFF &Symbol) {
361 GOFFSymbol ER(Symbol.getName(), Symbol.getIndex(), RootSD->getOrdinal(),
362 GOFF::ERAttr{Symbol.getCodeData(), Symbol.getBindingStrength(),
363 Symbol.getLinkage(), GOFF::ESD_AMODE_64,
364 Symbol.getBindingScope()});
365 writeSymbol(ER);
366}
367
368void GOFFWriter::defineSymbols() {
369 unsigned Ordinal = 0;
370 // Process all sections.
371 for (MCSection &S : Asm) {
372 auto &Section = static_cast<MCSectionGOFF &>(S);
373 Section.setOrdinal(++Ordinal);
374 defineSectionSymbols(Section);
375 }
376
377 // Process all symbols
378 for (const MCSymbol &Sym : Asm.symbols()) {
379 if (Sym.isTemporary())
380 continue;
381 auto &Symbol = static_cast<const MCSymbolGOFF &>(Sym);
382 if (!Symbol.isDefined()) {
383 Symbol.setIndex(++Ordinal);
384 defineExtern(Symbol);
385 } else if (Symbol.isInEDSection()) {
386 Symbol.setIndex(++Ordinal);
387 defineLabel(Symbol);
388 }
389 }
390}
391
392void GOFFWriter::writeHeader() {
393 OS.newRecord(GOFF::RT_HDR);
394 OS.write_zeros(1); // Reserved
395 OS.writebe<uint32_t>(0); // Target Hardware Environment
396 OS.writebe<uint32_t>(0); // Target Operating System Environment
397 OS.write_zeros(2); // Reserved
398 OS.writebe<uint16_t>(0); // CCSID
399 OS.write_zeros(16); // Character Set name
400 OS.write_zeros(16); // Language Product Identifier
401 OS.writebe<uint32_t>(1); // Architecture Level
402 OS.writebe<uint16_t>(0); // Module Properties Length
403 OS.write_zeros(6); // Reserved
404}
405
406void GOFFWriter::writeSymbol(const GOFFSymbol &Symbol) {
407 if (Symbol.Offset >= (((uint64_t)1) << 31))
408 report_fatal_error("ESD offset out of range");
409
410 // All symbol names are in EBCDIC.
411 SmallString<256> Name;
413
414 // Check length here since this number is technically signed but we need uint
415 // for writing to records.
416 if (Name.size() >= GOFF::MaxDataLength)
417 report_fatal_error("Symbol max name length exceeded");
418 uint16_t NameLength = Name.size();
419
420 OS.newRecord(GOFF::RT_ESD);
421 OS.writebe<uint8_t>(Symbol.SymbolType); // Symbol Type
422 OS.writebe<uint32_t>(Symbol.EsdId); // ESDID
423 OS.writebe<uint32_t>(Symbol.ParentEsdId); // Parent or Owning ESDID
424 OS.writebe<uint32_t>(0); // Reserved
425 OS.writebe<uint32_t>(
426 static_cast<uint32_t>(Symbol.Offset)); // Offset or Address
427 OS.writebe<uint32_t>(0); // Reserved
428 OS.writebe<uint32_t>(Symbol.SectionLength); // Length
429 OS.writebe<uint32_t>(Symbol.EASectionEDEsdId); // Extended Attribute ESDID
430 OS.writebe<uint32_t>(Symbol.EASectionOffset); // Extended Attribute Offset
431 OS.writebe<uint32_t>(0); // Reserved
432 OS.writebe<uint8_t>(Symbol.NameSpace); // Name Space ID
433 OS.writebe<uint8_t>(Symbol.SymbolFlags); // Flags
434 OS.writebe<uint8_t>(Symbol.FillByteValue); // Fill-Byte Value
435 OS.writebe<uint8_t>(0); // Reserved
436 OS.writebe<uint32_t>(Symbol.ADAEsdId); // ADA ESDID
437 OS.writebe<uint32_t>(Symbol.SortKey); // Sort Priority
438 OS.writebe<uint64_t>(0); // Reserved
439 for (auto F : Symbol.BehavAttrs.Attr)
440 OS.writebe<uint8_t>(F); // Behavioral Attributes
441 OS.writebe<uint16_t>(NameLength); // Name Length
442 OS.write(Name.data(), NameLength); // Name
443}
444
445namespace {
446/// Adapter stream to write a text section.
447class TextStream : public raw_ostream {
448 /// The underlying GOFFOstream.
449 GOFFOstream &OS;
450
451 /// The buffer size is the maximum number of bytes in a TXT section.
452 static constexpr size_t BufferSize = GOFF::MaxDataLength;
453
454 /// Static allocated buffer for the stream, used by the raw_ostream class. The
455 /// buffer is sized to hold the payload of a logical TXT record.
456 char Buffer[BufferSize];
457
458 /// The offset for the next TXT record. This is equal to the number of bytes
459 /// written.
460 size_t Offset;
461
462 /// The Esdid of the GOFF section.
463 const uint32_t EsdId;
464
465 /// The record style.
466 const GOFF::ESDTextStyle RecordStyle;
467
468 /// See raw_ostream::write_impl.
469 void write_impl(const char *Ptr, size_t Size) override;
470
471 uint64_t current_pos() const override { return Offset; }
472
473public:
474 explicit TextStream(GOFFOstream &OS, uint32_t EsdId,
475 GOFF::ESDTextStyle RecordStyle)
476 : OS(OS), Offset(0), EsdId(EsdId), RecordStyle(RecordStyle) {
477 SetBuffer(Buffer, sizeof(Buffer));
478 }
479
480 ~TextStream() override { flush(); }
481};
482} // namespace
483
484void TextStream::write_impl(const char *Ptr, size_t Size) {
485 size_t WrittenLength = 0;
486
487 // We only have signed 32bits of offset.
488 if (Offset + Size > std::numeric_limits<int32_t>::max())
489 report_fatal_error("TXT section too large");
490
491 while (WrittenLength < Size) {
492 size_t ToWriteLength =
493 std::min(Size - WrittenLength, size_t(GOFF::MaxDataLength));
494
495 OS.newRecord(GOFF::RT_TXT);
496 OS.writebe<uint8_t>(GOFF::Flags(4, 4, RecordStyle)); // Text Record Style
497 OS.writebe<uint32_t>(EsdId); // Element ESDID
498 OS.writebe<uint32_t>(0); // Reserved
499 OS.writebe<uint32_t>(static_cast<uint32_t>(Offset)); // Offset
500 OS.writebe<uint32_t>(0); // Text Field True Length
501 OS.writebe<uint16_t>(0); // Text Encoding
502 OS.writebe<uint16_t>(ToWriteLength); // Data Length
503 OS.write(Ptr + WrittenLength, ToWriteLength); // Data
504
505 WrittenLength += ToWriteLength;
506 Offset += ToWriteLength;
507 }
508}
509
510void GOFFWriter::writeText(const MCSectionGOFF *Section) {
511 // A BSS section contains only zeros, no need to write this.
512 if (Section->isBSS())
513 return;
514
515 TextStream S(OS, Section->getOrdinal(), Section->getTextStyle());
516 Asm.writeSectionData(S, Section);
517}
518
519namespace {
520// RelocDataItemBuffer provides a static buffer for relocation data items.
521class RelocDataItemBuffer {
522 char Buffer[GOFF::MaxDataLength];
523 char *Ptr;
524
525public:
526 RelocDataItemBuffer() : Ptr(Buffer) {}
527 const char *data() { return Buffer; }
528 size_t size() { return Ptr - Buffer; }
529 void reset() { Ptr = Buffer; }
530 bool fits(size_t S) { return size() + S < GOFF::MaxDataLength; }
531 template <typename T> void writebe(T Val) {
532 assert(fits(sizeof(T)) && "Out-of-bounds write");
534 Ptr += sizeof(T);
535 }
536};
537} // namespace
538
539void GOFFWriter::writeRelocations() {
540 // Set the IDs in the relocation entries.
541 for (auto &RelocEntry : Relocations) {
542 auto GetRptr = [](const MCSymbolGOFF *Sym) -> uint32_t {
543 if (Sym->isTemporary())
544 return static_cast<MCSectionGOFF &>(Sym->getSection())
545 .getBeginSymbol()
546 ->getIndex();
547 return Sym->getIndex();
548 };
549
550 RelocEntry.PEsdId = RelocEntry.Pptr->getOrdinal();
551 RelocEntry.REsdId = GetRptr(RelocEntry.Rptr);
552 }
553
554 // Sort relocation data items by the P pointer to save space.
555 std::sort(
556 Relocations.begin(), Relocations.end(),
557 [](const GOFFRelocationEntry &Left, const GOFFRelocationEntry &Right) {
558 return std::tie(Left.PEsdId, Left.REsdId, Left.POffset) <
559 std::tie(Right.PEsdId, Right.REsdId, Right.POffset);
560 });
561
562 // Construct the compressed relocation data items, and write them out.
563 RelocDataItemBuffer Buffer;
564 for (auto I = Relocations.begin(), E = Relocations.end(); I != E;) {
565 Buffer.reset();
566
567 uint32_t PrevResdId = -1;
568 uint32_t PrevPesdId = -1;
569 uint64_t PrevPOffset = -1;
570 for (; I != E; ++I) {
571 const GOFFRelocationEntry &Rel = *I;
572
573 bool SameREsdId = (Rel.REsdId == PrevResdId);
574 bool SamePEsdId = (Rel.PEsdId == PrevPesdId);
575 bool SamePOffset = (Rel.POffset == PrevPOffset);
576 bool EightByteOffset = ((Rel.POffset >> 32) & 0xffffffff);
577
578 // Calculate size of relocation data item, and check if it still fits into
579 // the record.
580 size_t ItemSize = 8; // Smallest size of a relocation data item.
581 if (!SameREsdId)
582 ItemSize += 4;
583 if (!SamePEsdId)
584 ItemSize += 4;
585 if (!SamePOffset)
586 ItemSize += (EightByteOffset ? 8 : 4);
587 if (!Buffer.fits(ItemSize))
588 break;
589
590 GOFF::Flags RelocFlags[6];
591 RelocFlags[0].set(0, 1, SameREsdId);
592 RelocFlags[0].set(1, 1, SamePEsdId);
593 RelocFlags[0].set(2, 1, SamePOffset);
594 RelocFlags[0].set(6, 1, EightByteOffset);
595
596 RelocFlags[1].set(0, 4, Rel.ReferenceType);
597 RelocFlags[1].set(4, 4, Rel.ReferentType);
598
599 RelocFlags[2].set(0, 7, Rel.Action);
600 RelocFlags[2].set(7, 1, Rel.FetchStore);
601
602 RelocFlags[4].set(0, 8, Rel.TargetLength);
603
604 for (auto F : RelocFlags)
605 Buffer.writebe<uint8_t>(F);
606 Buffer.writebe<uint16_t>(0); // Reserved.
607 if (!SameREsdId)
608 Buffer.writebe<uint32_t>(Rel.REsdId);
609 if (!SamePEsdId)
610 Buffer.writebe<uint32_t>(Rel.PEsdId);
611 if (!SamePOffset) {
612 if (EightByteOffset)
613 Buffer.writebe<uint64_t>(Rel.POffset);
614 else
615 Buffer.writebe<uint32_t>(Rel.POffset);
616 }
617
618 PrevResdId = Rel.REsdId;
619 PrevPesdId = Rel.PEsdId;
620 PrevPOffset = Rel.POffset;
621 }
622
623 OS.newRecord(GOFF::RT_RLD);
624 OS.writebe<uint8_t>(0); // Reserved.
625 OS.writebe<uint16_t>(Buffer.size()); // Length (of the relocation data).
626 OS.write(Buffer.data(), Buffer.size()); // Relocation Directory Data Items.
627 }
628}
629
630void GOFFWriter::writeEnd() {
631 uint8_t F = GOFF::END_EPR_None;
632 uint8_t AMODE = 0;
633 uint32_t ESDID = 0;
634
635 // TODO Set Flags/AMODE/ESDID for entry point.
636
637 OS.newRecord(GOFF::RT_END);
638 OS.writebe<uint8_t>(GOFF::Flags(6, 2, F)); // Indicator flags
639 OS.writebe<uint8_t>(AMODE); // AMODE
640 OS.write_zeros(3); // Reserved
641 // The record count is the number of logical records. In principle, this value
642 // is available as OS.logicalRecords(). However, some tools rely on this field
643 // being zero.
644 OS.writebe<uint32_t>(0); // Record Count
645 OS.writebe<uint32_t>(ESDID); // ESDID (of entry point)
646}
647
648uint64_t GOFFWriter::writeObject() {
649 writeHeader();
650
651 defineSymbols();
652
653 for (const MCSection &Section : Asm)
654 writeText(static_cast<const MCSectionGOFF *>(&Section));
655
656 writeRelocations();
657
658 writeEnd();
659
660 // Make sure all records are written.
661 OS.finalizeRecord();
662
663 LLVM_DEBUG(dbgs() << "Wrote " << OS.getNumLogicalRecords()
664 << " logical records.");
665
666 return OS.getWrittenSize();
667}
668
670 std::unique_ptr<MCGOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS)
671 : TargetObjectWriter(std::move(MOTW)), OS(OS) {}
672
674
676 const MCFixup &Fixup, MCValue Target,
677 uint64_t &FixedValue) {
678 const MCFixupKindInfo &FKI =
679 Asm->getBackend().getFixupKindInfo(Fixup.getKind());
680 const uint32_t Length = FKI.TargetSize / 8;
681 assert(FKI.TargetSize % 8 == 0 && "Target Size not multiple of 8");
682 const uint64_t FixupOffset = Asm->getFragmentOffset(F) + Fixup.getOffset();
683
684 unsigned RelocType = TargetObjectWriter->getRelocType(Target, Fixup);
685
686 const MCSectionGOFF *PSection = static_cast<MCSectionGOFF *>(F.getParent());
687 const auto &A = *static_cast<const MCSymbolGOFF *>(Target.getAddSym());
688 const MCSymbolGOFF *B = static_cast<const MCSymbolGOFF *>(Target.getSubSym());
690 if (A.isUndefined()) {
691 Asm->reportError(
692 Fixup.getLoc(),
693 Twine("symbol ")
694 .concat(A.getName())
695 .concat(" must be defined for a relative immediate relocation"));
696 return;
697 }
698 if (&A.getSection() != PSection) {
699 Asm->reportError(Fixup.getLoc(),
700 Twine("relative immediate relocation section mismatch: ")
701 .concat(A.getSection().getName())
702 .concat(" of symbol ")
703 .concat(A.getName())
704 .concat(" <-> ")
705 .concat(PSection->getName()));
706 return;
707 }
708 if (B) {
709 Asm->reportError(
710 Fixup.getLoc(),
711 Twine("subtractive symbol ")
712 .concat(B->getName())
713 .concat(" not supported for a relative immediate relocation"));
714 return;
715 }
716 FixedValue = Asm->getSymbolOffset(A) - FixupOffset + Target.getConstant();
717 return;
718 }
719 FixedValue = Target.getConstant();
720
721 // The symbol only has a section-relative offset if it is a temporary symbol.
722 FixedValue += A.isTemporary() ? Asm->getSymbolOffset(A) : 0;
723 A.setUsedInReloc();
724 if (B) {
725 FixedValue -= B->isTemporary() ? Asm->getSymbolOffset(*B) : 0;
726 B->setUsedInReloc();
727 }
728
729 // UseQCon causes class offsets versus absolute addresses to be used. This
730 // is analogous to using QCONs in older OBJ object file format.
731 bool UseQCon = RelocType == MCGOFFObjectTargetWriter::Reloc_Type_QCon;
732
733 GOFF::RLDFetchStore FetchStore =
739 B == nullptr && "No dependent relocations expected");
740
742 enum GOFF::RLDReferentType ReferentType = GOFF::RLD_RO_Label;
743 if (UseQCon) {
745 ReferentType = GOFF::RLD_RO_Class;
746 }
749
750 auto DumpReloc = [&PSection, &ReferenceType, &FixupOffset,
751 &FixedValue](const char *N, const MCSymbolGOFF *Sym) {
752 const char *Con;
753 switch (ReferenceType) {
755 Con = "ACon";
756 break;
758 Con = "QCon";
759 break;
761 Con = "VCon";
762 break;
763 default:
764 Con = "(unknown)";
765 }
766 dbgs() << "Reloc " << N << ": " << Con << " Rptr: " << Sym->getName()
767 << " Pptr: " << PSection->getName() << " Offset: " << FixupOffset
768 << " Fixed Imm: " << FixedValue << "\n";
769 };
770 (void)DumpReloc;
771
772 // Save relocation data for later writing.
773 LLVM_DEBUG(DumpReloc("A", &A));
774 Relocations.emplace_back(PSection, &A, ReferenceType, ReferentType,
775 GOFF::RLD_ACT_Add, FetchStore, FixupOffset, Length);
776 if (B) {
777 LLVM_DEBUG(DumpReloc("B", B));
778 Relocations.emplace_back(
779 PSection, B, ReferenceType, ReferentType, GOFF::RLD_ACT_Subtract,
781 }
782}
783
785 uint64_t Size = GOFFWriter(OS, *Asm, RootSD, Relocations).writeObject();
786 return Size;
787}
788
789std::unique_ptr<MCObjectWriter>
790llvm::createGOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW,
791 raw_pwrite_stream &OS) {
792 return std::make_unique<GOFFObjectWriter>(std::move(MOTW), OS);
793}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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:335
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
PowerPC TLS Dynamic Call Fixup
static Split data
#define LLVM_DEBUG(...)
Definition Debug.h:114
GOFFObjectWriter(std::unique_ptr< MCGOFFObjectTargetWriter > MOTW, raw_pwrite_stream &OS)
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:216
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:61
GOFF::EDAttr getEDAttributes() const
unsigned getOrdinal() const
Definition MCSection.h:609
StringRef getName() const
Definition MCSection.h:586
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:45
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)
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
@ 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
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
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)
Definition Endian.h:44
void write(void *memory, value_type value, endianness endian)
Write a value to memory with a particular endianness.
Definition Endian.h:96
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:532
@ Length
Definition DWP.cpp:532
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:1667
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:1150
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:167
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:1888
LLVM_ABI Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue, Dwarf64StrOffsetsPromotion StrOffsetsOptValue)
Definition DWP.cpp:677
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:870
#define N
GOFF::RLDReferenceType ReferenceType
GOFF::RLDFetchStore FetchStore
GOFF::RLDReferentType ReferentType
GOFF::ESDReserveQwords ReservedQwords
GOFF::ESDRmode Rmode
GOFF::ESDAlignment Alignment
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::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.