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 13 #include "llvm/BinaryFormat/GOFF.h" 14 #include "llvm/MC/MCAssembler.h" 15 #include "llvm/MC/MCGOFFAttributes.h" 16 #include "llvm/MC/MCGOFFObjectWriter.h" 17 #include "llvm/MC/MCSectionGOFF.h" 18 #include "llvm/MC/MCSymbolGOFF.h" 19 #include "llvm/MC/MCValue.h" 20 #include "llvm/Support/Casting.h" 21 #include "llvm/Support/ConvertEBCDIC.h" 22 #include "llvm/Support/Debug.h" 23 #include "llvm/Support/Endian.h" 24 #include "llvm/Support/raw_ostream.h" 25 26 using namespace llvm; 27 28 #define DEBUG_TYPE "goff-writer" 29 30 namespace { 31 // Common flag values on records. 32 33 // Flag: This record is continued. 34 constexpr uint8_t RecContinued = GOFF::Flags(7, 1, 1); 35 36 // Flag: This record is a continuation. 37 constexpr 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. 50 class GOFFOstream { 51 /// The underlying raw_pwrite_stream. 52 raw_pwrite_stream &OS; 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 73 public: 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 = 90 support::endian::byte_swap<value_type>(Value, llvm::endianness::big); 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 100 private: 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 110 GOFFOstream::GOFFOstream(raw_pwrite_stream &OS) : OS(OS) {} 111 112 GOFFOstream::~GOFFOstream() { finalizeRecord(); } 113 114 void 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 130 size_t GOFFOstream::getRemainingSize() { 131 return size_t(&Buffer[BufferSize] - BufferPtr); 132 } 133 134 void 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 166 void 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 184 void GOFFOstream::newRecord(GOFF::RecordType Type) { 185 finalizeRecord(); 186 TypeAndFlags = Type << 4; 187 ++LogicalRecords; 188 } 189 190 void 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 199 namespace { 200 // A GOFFSymbol holds all the data required for writing an ESD record. 201 class GOFFSymbol { 202 public: 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. 209 GOFF::ESDSymbolType SymbolType; 210 GOFF::ESDNameSpaceId NameSpace = GOFF::ESD_NS_ProgramManagementBinder; 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), 225 SymbolType(GOFF::ESD_ST_SectionDefinition) { 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), 233 SymbolType(GOFF::ESD_ST_ElementDefinition) { 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 272 class GOFFWriter { 273 GOFFOstream OS; 274 MCAssembler &Asm; 275 276 void writeHeader(); 277 void writeSymbol(const GOFFSymbol &Symbol); 278 void writeText(const MCSectionGOFF *MC); 279 void writeEnd(); 280 281 void defineSectionSymbols(const MCSectionGOFF &Section); 282 void defineLabel(const MCSymbolGOFF &Symbol); 283 void defineSymbols(); 284 285 public: 286 GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm); 287 uint64_t writeObject(); 288 }; 289 } // namespace 290 291 GOFFWriter::GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm) 292 : OS(OS), Asm(Asm) {} 293 294 void GOFFWriter::defineSectionSymbols(const MCSectionGOFF &Section) { 295 if (Section.isSD()) { 296 GOFFSymbol SD(Section.getName(), Section.getOrdinal(), 297 Section.getSDAttributes()); 298 writeSymbol(SD); 299 } 300 301 if (Section.isED()) { 302 GOFFSymbol ED(Section.getName(), Section.getOrdinal(), 303 Section.getParent()->getOrdinal(), Section.getEDAttributes()); 304 ED.SectionLength = Asm.getSectionAddressSize(Section); 305 writeSymbol(ED); 306 } 307 308 if (Section.isPR()) { 309 MCSectionGOFF *Parent = Section.getParent(); 310 GOFFSymbol PR(Section.getName(), Section.getOrdinal(), Parent->getOrdinal(), 311 Parent->getEDAttributes(), Section.getPRAttributes()); 312 PR.SectionLength = Asm.getSectionAddressSize(Section); 313 if (Section.requiresNonZeroLength()) { 314 // We cannot have a zero-length section for data. If we do, 315 // artificially inflate it. Use 2 bytes to avoid odd alignments. Note: 316 // if this is ever changed, you will need to update the code in 317 // SystemZAsmPrinter::emitCEEMAIN and SystemZAsmPrinter::emitCELQMAIN to 318 // generate -1 if there is no ADA 319 if (!PR.SectionLength) 320 PR.SectionLength = 2; 321 } 322 writeSymbol(PR); 323 } 324 } 325 326 void GOFFWriter::defineLabel(const MCSymbolGOFF &Symbol) { 327 MCSectionGOFF &Section = static_cast<MCSectionGOFF &>(Symbol.getSection()); 328 GOFFSymbol LD(Symbol.getName(), Symbol.getIndex(), Section.getOrdinal(), 329 Section.getEDAttributes().NameSpace, Symbol.getLDAttributes()); 330 if (Symbol.getADA()) 331 LD.ADAEsdId = Symbol.getADA()->getOrdinal(); 332 writeSymbol(LD); 333 } 334 335 void GOFFWriter::defineSymbols() { 336 unsigned Ordinal = 0; 337 // Process all sections. 338 for (MCSection &S : Asm) { 339 auto &Section = cast<MCSectionGOFF>(S); 340 Section.setOrdinal(++Ordinal); 341 defineSectionSymbols(Section); 342 } 343 344 // Process all symbols 345 for (const MCSymbol &Sym : Asm.symbols()) { 346 if (Sym.isTemporary()) 347 continue; 348 auto &Symbol = cast<MCSymbolGOFF>(Sym); 349 if (Symbol.hasLDAttributes()) { 350 Symbol.setIndex(++Ordinal); 351 defineLabel(Symbol); 352 } 353 } 354 } 355 356 void GOFFWriter::writeHeader() { 357 OS.newRecord(GOFF::RT_HDR); 358 OS.write_zeros(1); // Reserved 359 OS.writebe<uint32_t>(0); // Target Hardware Environment 360 OS.writebe<uint32_t>(0); // Target Operating System Environment 361 OS.write_zeros(2); // Reserved 362 OS.writebe<uint16_t>(0); // CCSID 363 OS.write_zeros(16); // Character Set name 364 OS.write_zeros(16); // Language Product Identifier 365 OS.writebe<uint32_t>(1); // Architecture Level 366 OS.writebe<uint16_t>(0); // Module Properties Length 367 OS.write_zeros(6); // Reserved 368 } 369 370 void GOFFWriter::writeSymbol(const GOFFSymbol &Symbol) { 371 if (Symbol.Offset >= (((uint64_t)1) << 31)) 372 report_fatal_error("ESD offset out of range"); 373 374 // All symbol names are in EBCDIC. 375 SmallString<256> Name; 376 ConverterEBCDIC::convertToEBCDIC(Symbol.Name, Name); 377 378 // Check length here since this number is technically signed but we need uint 379 // for writing to records. 380 if (Name.size() >= GOFF::MaxDataLength) 381 report_fatal_error("Symbol max name length exceeded"); 382 uint16_t NameLength = Name.size(); 383 384 OS.newRecord(GOFF::RT_ESD); 385 OS.writebe<uint8_t>(Symbol.SymbolType); // Symbol Type 386 OS.writebe<uint32_t>(Symbol.EsdId); // ESDID 387 OS.writebe<uint32_t>(Symbol.ParentEsdId); // Parent or Owning ESDID 388 OS.writebe<uint32_t>(0); // Reserved 389 OS.writebe<uint32_t>( 390 static_cast<uint32_t>(Symbol.Offset)); // Offset or Address 391 OS.writebe<uint32_t>(0); // Reserved 392 OS.writebe<uint32_t>(Symbol.SectionLength); // Length 393 OS.writebe<uint32_t>(Symbol.EASectionEDEsdId); // Extended Attribute ESDID 394 OS.writebe<uint32_t>(Symbol.EASectionOffset); // Extended Attribute Offset 395 OS.writebe<uint32_t>(0); // Reserved 396 OS.writebe<uint8_t>(Symbol.NameSpace); // Name Space ID 397 OS.writebe<uint8_t>(Symbol.SymbolFlags); // Flags 398 OS.writebe<uint8_t>(Symbol.FillByteValue); // Fill-Byte Value 399 OS.writebe<uint8_t>(0); // Reserved 400 OS.writebe<uint32_t>(Symbol.ADAEsdId); // ADA ESDID 401 OS.writebe<uint32_t>(Symbol.SortKey); // Sort Priority 402 OS.writebe<uint64_t>(0); // Reserved 403 for (auto F : Symbol.BehavAttrs.Attr) 404 OS.writebe<uint8_t>(F); // Behavioral Attributes 405 OS.writebe<uint16_t>(NameLength); // Name Length 406 OS.write(Name.data(), NameLength); // Name 407 } 408 409 namespace { 410 /// Adapter stream to write a text section. 411 class TextStream : public raw_ostream { 412 /// The underlying GOFFOstream. 413 GOFFOstream &OS; 414 415 /// The buffer size is the maximum number of bytes in a TXT section. 416 static constexpr size_t BufferSize = GOFF::MaxDataLength; 417 418 /// Static allocated buffer for the stream, used by the raw_ostream class. The 419 /// buffer is sized to hold the payload of a logical TXT record. 420 char Buffer[BufferSize]; 421 422 /// The offset for the next TXT record. This is equal to the number of bytes 423 /// written. 424 size_t Offset; 425 426 /// The Esdid of the GOFF section. 427 const uint32_t EsdId; 428 429 /// The record style. 430 const GOFF::ESDTextStyle RecordStyle; 431 432 /// See raw_ostream::write_impl. 433 void write_impl(const char *Ptr, size_t Size) override; 434 435 uint64_t current_pos() const override { return Offset; } 436 437 public: 438 explicit TextStream(GOFFOstream &OS, uint32_t EsdId, 439 GOFF::ESDTextStyle RecordStyle) 440 : OS(OS), Offset(0), EsdId(EsdId), RecordStyle(RecordStyle) { 441 SetBuffer(Buffer, sizeof(Buffer)); 442 } 443 444 ~TextStream() { flush(); } 445 }; 446 } // namespace 447 448 void TextStream::write_impl(const char *Ptr, size_t Size) { 449 size_t WrittenLength = 0; 450 451 // We only have signed 32bits of offset. 452 if (Offset + Size > std::numeric_limits<int32_t>::max()) 453 report_fatal_error("TXT section too large"); 454 455 while (WrittenLength < Size) { 456 size_t ToWriteLength = 457 std::min(Size - WrittenLength, size_t(GOFF::MaxDataLength)); 458 459 OS.newRecord(GOFF::RT_TXT); 460 OS.writebe<uint8_t>(GOFF::Flags(4, 4, RecordStyle)); // Text Record Style 461 OS.writebe<uint32_t>(EsdId); // Element ESDID 462 OS.writebe<uint32_t>(0); // Reserved 463 OS.writebe<uint32_t>(static_cast<uint32_t>(Offset)); // Offset 464 OS.writebe<uint32_t>(0); // Text Field True Length 465 OS.writebe<uint16_t>(0); // Text Encoding 466 OS.writebe<uint16_t>(ToWriteLength); // Data Length 467 OS.write(Ptr + WrittenLength, ToWriteLength); // Data 468 469 WrittenLength += ToWriteLength; 470 Offset += ToWriteLength; 471 } 472 } 473 474 void GOFFWriter::writeText(const MCSectionGOFF *Section) { 475 // A BSS section contains only zeros, no need to write this. 476 if (Section->isBSS()) 477 return; 478 479 TextStream S(OS, Section->getOrdinal(), Section->getTextStyle()); 480 Asm.writeSectionData(S, Section); 481 } 482 483 void GOFFWriter::writeEnd() { 484 uint8_t F = GOFF::END_EPR_None; 485 uint8_t AMODE = 0; 486 uint32_t ESDID = 0; 487 488 // TODO Set Flags/AMODE/ESDID for entry point. 489 490 OS.newRecord(GOFF::RT_END); 491 OS.writebe<uint8_t>(GOFF::Flags(6, 2, F)); // Indicator flags 492 OS.writebe<uint8_t>(AMODE); // AMODE 493 OS.write_zeros(3); // Reserved 494 // The record count is the number of logical records. In principle, this value 495 // is available as OS.logicalRecords(). However, some tools rely on this field 496 // being zero. 497 OS.writebe<uint32_t>(0); // Record Count 498 OS.writebe<uint32_t>(ESDID); // ESDID (of entry point) 499 } 500 501 uint64_t GOFFWriter::writeObject() { 502 writeHeader(); 503 504 defineSymbols(); 505 506 for (const MCSection &Section : Asm) 507 writeText(static_cast<const MCSectionGOFF *>(&Section)); 508 509 writeEnd(); 510 511 // Make sure all records are written. 512 OS.finalizeRecord(); 513 514 LLVM_DEBUG(dbgs() << "Wrote " << OS.getNumLogicalRecords() 515 << " logical records."); 516 517 return OS.getWrittenSize(); 518 } 519 520 GOFFObjectWriter::GOFFObjectWriter( 521 std::unique_ptr<MCGOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS) 522 : TargetObjectWriter(std::move(MOTW)), OS(OS) {} 523 524 GOFFObjectWriter::~GOFFObjectWriter() {} 525 526 uint64_t GOFFObjectWriter::writeObject() { 527 uint64_t Size = GOFFWriter(OS, *Asm).writeObject(); 528 return Size; 529 } 530 531 std::unique_ptr<MCObjectWriter> 532 llvm::createGOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW, 533 raw_pwrite_stream &OS) { 534 return std::make_unique<GOFFObjectWriter>(std::move(MOTW), OS); 535 } 536