901 lines · cpp
1//===- yaml2xcoff - Convert YAML to a xcoff object file -------------------===//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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// The xcoff component of yaml2obj.11///12//===----------------------------------------------------------------------===//13 14#include "llvm/ADT/DenseMap.h"15#include "llvm/BinaryFormat/XCOFF.h"16#include "llvm/MC/StringTableBuilder.h"17#include "llvm/Object/XCOFFObjectFile.h"18#include "llvm/ObjectYAML/ObjectYAML.h"19#include "llvm/ObjectYAML/yaml2obj.h"20#include "llvm/Support/EndianStream.h"21#include "llvm/Support/MemoryBuffer.h"22#include "llvm/Support/raw_ostream.h"23 24using namespace llvm;25using namespace llvm::object;26 27namespace {28 29constexpr unsigned DefaultSectionAlign = 4;30constexpr int16_t MaxSectionIndex = INT16_MAX;31constexpr uint32_t MaxRawDataSize = UINT32_MAX;32 33class XCOFFWriter {34public:35 XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH)36 : Obj(Obj), W(OS, llvm::endianness::big), ErrHandler(EH),37 StrTblBuilder(StringTableBuilder::XCOFF) {38 Is64Bit = Obj.Header.Magic == (llvm::yaml::Hex16)XCOFF::XCOFF64;39 }40 bool writeXCOFF();41 42private:43 void reportOverwrite(uint64_t currentOffset, uint64_t specifiedOffset,44 const Twine &fieldName);45 bool nameShouldBeInStringTable(StringRef SymbolName);46 bool initFileHeader(uint64_t CurrentOffset);47 void initAuxFileHeader();48 bool initSectionHeaders(uint64_t &CurrentOffset);49 bool initRelocations(uint64_t &CurrentOffset);50 bool initStringTable();51 bool assignAddressesAndIndices();52 53 void writeFileHeader();54 void writeAuxFileHeader();55 void writeSectionHeaders();56 bool writeSectionData();57 bool writeRelocations();58 bool writeSymbols();59 void writeStringTable();60 61 bool writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym);62 bool writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym);63 bool writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym);64 bool writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym);65 bool writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym);66 bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym);67 bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym);68 bool writeAuxSymbol(const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym);69 70 XCOFFYAML::Object &Obj;71 bool Is64Bit = false;72 support::endian::Writer W;73 yaml::ErrorHandler ErrHandler;74 StringTableBuilder StrTblBuilder;75 uint64_t StartOffset = 0u;76 // Map the section name to its corrresponding section index.77 DenseMap<StringRef, int16_t> SectionIndexMap = {78 {StringRef("N_DEBUG"), XCOFF::N_DEBUG},79 {StringRef("N_ABS"), XCOFF::N_ABS},80 {StringRef("N_UNDEF"), XCOFF::N_UNDEF}};81 XCOFFYAML::FileHeader InitFileHdr = Obj.Header;82 XCOFFYAML::AuxiliaryHeader InitAuxFileHdr;83 std::vector<XCOFFYAML::Section> InitSections = Obj.Sections;84};85 86static void writeName(StringRef StrName, support::endian::Writer W) {87 char Name[XCOFF::NameSize];88 memset(Name, 0, XCOFF::NameSize);89 char SrcName[] = "";90 memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size());91 ArrayRef<char> NameRef(Name, XCOFF::NameSize);92 W.write(NameRef);93}94 95void XCOFFWriter::reportOverwrite(uint64_t CurrentOffset,96 uint64_t specifiedOffset,97 const Twine &fieldName) {98 ErrHandler("current file offset (" + Twine(CurrentOffset) +99 ") is bigger than the specified " + fieldName + " (" +100 Twine(specifiedOffset) + ") ");101}102 103bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) {104 // For XCOFF64: The symbol name is always in the string table.105 return (SymbolName.size() > XCOFF::NameSize) || Is64Bit;106}107 108bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) {109 for (XCOFFYAML::Section &InitSection : InitSections) {110 if (!InitSection.Relocations.empty()) {111 uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64112 : XCOFF::RelocationSerializationSize32;113 uint64_t UsedSize = RelSize * InitSection.Relocations.size();114 115 // If NumberOfRelocations was specified, we use it, even if it's116 // not consistent with the number of provided relocations.117 if (!InitSection.NumberOfRelocations)118 InitSection.NumberOfRelocations = InitSection.Relocations.size();119 120 // If the YAML file specified an offset to relocations, we use it.121 if (InitSection.FileOffsetToRelocations) {122 if (CurrentOffset > InitSection.FileOffsetToRelocations) {123 reportOverwrite(CurrentOffset, InitSection.FileOffsetToRelocations,124 "FileOffsetToRelocations for the " +125 InitSection.SectionName + " section");126 return false;127 }128 CurrentOffset = InitSection.FileOffsetToRelocations;129 } else130 InitSection.FileOffsetToRelocations = CurrentOffset;131 CurrentOffset += UsedSize;132 if (CurrentOffset > MaxRawDataSize) {133 ErrHandler("maximum object size (" + Twine(MaxRawDataSize) +134 ") exceeded when writing relocation data for section " +135 Twine(InitSection.SectionName));136 return false;137 }138 }139 }140 return true;141}142 143bool XCOFFWriter::initSectionHeaders(uint64_t &CurrentOffset) {144 uint64_t CurrentEndDataAddr = 0;145 uint64_t CurrentEndTDataAddr = 0;146 for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {147 // Assign indices for sections.148 if (InitSections[I].SectionName.size()) {149 int16_t &SectionIndex = SectionIndexMap[InitSections[I].SectionName];150 if (!SectionIndex) {151 // The section index starts from 1.152 SectionIndex = I + 1;153 if ((I + 1) > MaxSectionIndex) {154 ErrHandler("exceeded the maximum permitted section index of " +155 Twine(MaxSectionIndex));156 return false;157 }158 }159 }160 161 if (!InitSections[I].Size)162 InitSections[I].Size = InitSections[I].SectionData.binary_size();163 164 // Section data addresses (physical/virtual) are related to symbol165 // addresses and alignments. Furthermore, it is possible to specify the166 // same starting addresses for the .text, .data, and .tdata sections.167 // Without examining all the symbols and their addreses and alignments,168 // it is not possible to compute valid section addresses. The only169 // condition required by XCOFF is that the .bss section immediately170 // follows the .data section, and the .tbss section immediately follows171 // the .tdata section. Therefore, we only assign addresses to the .bss172 // and .tbss sections if they do not already have non-zero addresses.173 // (If the YAML file is being used to generate a valid object file, we174 // expect all section addresses to be specified explicitly.)175 switch (InitSections[I].Flags) {176 case XCOFF::STYP_DATA:177 CurrentEndDataAddr = InitSections[I].Address + InitSections[I].Size;178 break;179 case XCOFF::STYP_BSS:180 if (!InitSections[I].Address)181 InitSections[I].Address = CurrentEndDataAddr;182 break;183 case XCOFF::STYP_TDATA:184 CurrentEndTDataAddr = InitSections[I].Address + InitSections[I].Size;185 break;186 case XCOFF::STYP_TBSS:187 if (!InitSections[I].Address)188 InitSections[I].Address = CurrentEndTDataAddr;189 break;190 }191 192 if (InitSections[I].SectionData.binary_size()) {193 if (InitSections[I].FileOffsetToData) {194 // Use the providedFileOffsetToData.195 if (CurrentOffset > InitSections[I].FileOffsetToData) {196 reportOverwrite(CurrentOffset, InitSections[I].FileOffsetToData,197 "FileOffsetToData for the " +198 InitSections[I].SectionName + " section");199 return false;200 }201 CurrentOffset = InitSections[I].FileOffsetToData;202 } else {203 CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign);204 InitSections[I].FileOffsetToData = CurrentOffset;205 }206 CurrentOffset += InitSections[I].SectionData.binary_size();207 if (CurrentOffset > MaxRawDataSize) {208 ErrHandler("maximum object size (" + Twine(MaxRawDataSize) +209 ") exceeded when writing data for section " + Twine(I + 1) +210 " (" + Twine(InitSections[I].SectionName) + ")");211 return false;212 }213 }214 if (InitSections[I].SectionSubtype) {215 uint32_t DWARFSubtype =216 static_cast<uint32_t>(*InitSections[I].SectionSubtype);217 if (InitSections[I].Flags != XCOFF::STYP_DWARF) {218 ErrHandler("a DWARFSectionSubtype is only allowed for a DWARF section");219 return false;220 }221 unsigned Mask = Is64Bit ? XCOFFSectionHeader64::SectionFlagsTypeMask222 : XCOFFSectionHeader32::SectionFlagsTypeMask;223 if (DWARFSubtype & Mask) {224 ErrHandler("the low-order bits of DWARFSectionSubtype must be 0");225 return false;226 }227 InitSections[I].Flags |= DWARFSubtype;228 }229 }230 return initRelocations(CurrentOffset);231}232 233bool XCOFFWriter::initStringTable() {234 if (Obj.StrTbl.RawContent) {235 size_t RawSize = Obj.StrTbl.RawContent->binary_size();236 if (Obj.StrTbl.Strings || Obj.StrTbl.Length) {237 ErrHandler(238 "can't specify Strings or Length when RawContent is specified");239 return false;240 }241 if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) {242 ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +243 ") is less than the RawContent data size (" + Twine(RawSize) +244 ")");245 return false;246 }247 return true;248 }249 if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) {250 ErrHandler("ContentSize shouldn't be less than 4 without RawContent");251 return false;252 }253 254 // Build the string table.255 StrTblBuilder.clear();256 257 if (Obj.StrTbl.Strings) {258 // Add all specified strings to the string table.259 for (StringRef StringEnt : *Obj.StrTbl.Strings)260 StrTblBuilder.add(StringEnt);261 262 size_t StrTblIdx = 0;263 size_t NumOfStrings = Obj.StrTbl.Strings->size();264 for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {265 if (nameShouldBeInStringTable(YamlSym.SymbolName)) {266 if (StrTblIdx < NumOfStrings) {267 // Overwrite the symbol name with the specified string.268 YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx];269 ++StrTblIdx;270 } else271 // Names that are not overwritten are still stored in the string272 // table.273 StrTblBuilder.add(YamlSym.SymbolName);274 }275 }276 } else {277 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {278 if (nameShouldBeInStringTable(YamlSym.SymbolName))279 StrTblBuilder.add(YamlSym.SymbolName);280 }281 }282 283 // Check if the file name in the File Auxiliary Entry should be added to the284 // string table.285 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {286 for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym :287 YamlSym.AuxEntries) {288 if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get()))289 if (nameShouldBeInStringTable(AS->FileNameOrString.value_or("")))290 StrTblBuilder.add(AS->FileNameOrString.value_or(""));291 }292 }293 294 StrTblBuilder.finalize();295 296 size_t StrTblSize = StrTblBuilder.getSize();297 if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) {298 ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +299 ") is less than the size of the data that would otherwise be "300 "written (" +301 Twine(StrTblSize) + ")");302 return false;303 }304 305 return true;306}307 308bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) {309 // The default format of the object file is XCOFF32.310 InitFileHdr.Magic = XCOFF::XCOFF32;311 InitFileHdr.NumberOfSections = Obj.Sections.size();312 InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size();313 314 for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {315 uint32_t AuxCount = YamlSym.AuxEntries.size();316 if (YamlSym.NumberOfAuxEntries && *YamlSym.NumberOfAuxEntries < AuxCount) {317 ErrHandler("specified NumberOfAuxEntries " +318 Twine(static_cast<uint32_t>(*YamlSym.NumberOfAuxEntries)) +319 " is less than the actual number "320 "of auxiliary entries " +321 Twine(AuxCount));322 return false;323 }324 YamlSym.NumberOfAuxEntries = YamlSym.NumberOfAuxEntries.value_or(AuxCount);325 // Add the number of auxiliary symbols to the total number.326 InitFileHdr.NumberOfSymTableEntries += *YamlSym.NumberOfAuxEntries;327 }328 329 // Calculate SymbolTableOffset for the file header.330 if (InitFileHdr.NumberOfSymTableEntries) {331 if (Obj.Header.SymbolTableOffset) {332 if (CurrentOffset > Obj.Header.SymbolTableOffset) {333 reportOverwrite(CurrentOffset, Obj.Header.SymbolTableOffset,334 "SymbolTableOffset");335 return false;336 }337 CurrentOffset = Obj.Header.SymbolTableOffset;338 }339 InitFileHdr.SymbolTableOffset = CurrentOffset;340 CurrentOffset +=341 InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize;342 if (CurrentOffset > MaxRawDataSize) {343 ErrHandler("maximum object size of " + Twine(MaxRawDataSize) +344 " exceeded when writing symbols");345 return false;346 }347 }348 // TODO: Calculate FileOffsetToLineNumbers when line number supported.349 return true;350}351 352void XCOFFWriter::initAuxFileHeader() {353 if (Obj.AuxHeader)354 InitAuxFileHdr = *Obj.AuxHeader;355 // In general, an object file might contain multiple sections of a given type,356 // but in a loadable module, there must be exactly one .text, .data, .bss, and357 // .loader section. A loadable object might also have one .tdata section and358 // one .tbss section.359 // Set these section-related values if not set explicitly. We assume that the360 // input YAML matches the format of the loadable object, but if multiple input361 // sections still have the same type, the first section with that type362 // prevails.363 for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {364 switch (InitSections[I].Flags) {365 case XCOFF::STYP_TEXT:366 if (!InitAuxFileHdr.TextSize)367 InitAuxFileHdr.TextSize = InitSections[I].Size;368 if (!InitAuxFileHdr.TextStartAddr)369 InitAuxFileHdr.TextStartAddr = InitSections[I].Address;370 if (!InitAuxFileHdr.SecNumOfText)371 InitAuxFileHdr.SecNumOfText = I + 1;372 break;373 case XCOFF::STYP_DATA:374 if (!InitAuxFileHdr.InitDataSize)375 InitAuxFileHdr.InitDataSize = InitSections[I].Size;376 if (!InitAuxFileHdr.DataStartAddr)377 InitAuxFileHdr.DataStartAddr = InitSections[I].Address;378 if (!InitAuxFileHdr.SecNumOfData)379 InitAuxFileHdr.SecNumOfData = I + 1;380 break;381 case XCOFF::STYP_BSS:382 if (!InitAuxFileHdr.BssDataSize)383 InitAuxFileHdr.BssDataSize = InitSections[I].Size;384 if (!InitAuxFileHdr.SecNumOfBSS)385 InitAuxFileHdr.SecNumOfBSS = I + 1;386 break;387 case XCOFF::STYP_TDATA:388 if (!InitAuxFileHdr.SecNumOfTData)389 InitAuxFileHdr.SecNumOfTData = I + 1;390 break;391 case XCOFF::STYP_TBSS:392 if (!InitAuxFileHdr.SecNumOfTBSS)393 InitAuxFileHdr.SecNumOfTBSS = I + 1;394 break;395 case XCOFF::STYP_LOADER:396 if (!InitAuxFileHdr.SecNumOfLoader)397 InitAuxFileHdr.SecNumOfLoader = I + 1;398 break;399 default:400 break;401 }402 }403}404 405bool XCOFFWriter::assignAddressesAndIndices() {406 uint64_t FileHdrSize =407 Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32;408 409 // If AuxHeaderSize is specified in the YAML file, we construct410 // an auxiliary header.411 uint64_t AuxFileHdrSize = 0;412 413 if (Obj.Header.AuxHeaderSize)414 AuxFileHdrSize = Obj.Header.AuxHeaderSize;415 else if (Obj.AuxHeader)416 AuxFileHdrSize =417 (Is64Bit ? XCOFF::AuxFileHeaderSize64 : XCOFF::AuxFileHeaderSize32);418 uint64_t SecHdrSize =419 Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32;420 uint64_t CurrentOffset =421 FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize;422 423 // Calculate section header info.424 if (!initSectionHeaders(CurrentOffset))425 return false;426 427 // Calculate file header info.428 if (!initFileHeader(CurrentOffset))429 return false;430 InitFileHdr.AuxHeaderSize = AuxFileHdrSize;431 432 // Initialize the auxiliary file header.433 if (AuxFileHdrSize)434 initAuxFileHeader();435 436 // Initialize the string table.437 return initStringTable();438}439 440void XCOFFWriter::writeFileHeader() {441 W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic);442 W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections443 : InitFileHdr.NumberOfSections);444 W.write<int32_t>(Obj.Header.TimeStamp);445 if (Is64Bit) {446 W.write<uint64_t>(InitFileHdr.SymbolTableOffset);447 W.write<uint16_t>(InitFileHdr.AuxHeaderSize);448 W.write<uint16_t>(Obj.Header.Flags);449 W.write<int32_t>(Obj.Header.NumberOfSymTableEntries450 ? Obj.Header.NumberOfSymTableEntries451 : InitFileHdr.NumberOfSymTableEntries);452 } else {453 W.write<uint32_t>(InitFileHdr.SymbolTableOffset);454 W.write<int32_t>(Obj.Header.NumberOfSymTableEntries455 ? Obj.Header.NumberOfSymTableEntries456 : InitFileHdr.NumberOfSymTableEntries);457 W.write<uint16_t>(InitFileHdr.AuxHeaderSize);458 W.write<uint16_t>(Obj.Header.Flags);459 }460}461 462void XCOFFWriter::writeAuxFileHeader() {463 W.write<uint16_t>(InitAuxFileHdr.Magic.value_or(yaml::Hex16(1)));464 W.write<uint16_t>(InitAuxFileHdr.Version.value_or(yaml::Hex16(1)));465 if (Is64Bit) {466 W.OS.write_zeros(4); // Reserved for debugger.467 W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0)));468 W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0)));469 W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0)));470 } else {471 W.write<uint32_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0)));472 W.write<uint32_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0)));473 W.write<uint32_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0)));474 W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0)));475 W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0)));476 W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0)));477 // A short 32-bit auxiliary header ends here.478 if (InitFileHdr.AuxHeaderSize == XCOFF::AuxFileHeaderSizeShort)479 return;480 W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0)));481 }482 W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.value_or(0));483 W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.value_or(0));484 W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.value_or(0));485 W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.value_or(0));486 W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.value_or(0));487 W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.value_or(0));488 W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.value_or(yaml::Hex16(0)));489 W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.value_or(yaml::Hex16(0)));490 W.write<uint16_t>(InitAuxFileHdr.ModuleType.value_or(yaml::Hex16(0)));491 W.write<uint8_t>(InitAuxFileHdr.CpuFlag.value_or(yaml::Hex8(0)));492 W.write<uint8_t>(0); // Reserved for CPU type.493 if (Is64Bit) {494 W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0)));495 W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0)));496 W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0)));497 W.write<uint8_t>(498 InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0x80)));499 W.write<uint64_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0)));500 W.write<uint64_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0)));501 W.write<uint64_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0)));502 W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0)));503 W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0)));504 W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0)));505 } else {506 W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0)));507 W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0)));508 W.OS.write_zeros(4); // Reserved for debugger.509 W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0)));510 W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0)));511 W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0)));512 W.write<uint8_t>(513 InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0)));514 }515 W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.value_or(0));516 W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.value_or(0));517 if (Is64Bit) {518 W.write<uint16_t>(519 InitAuxFileHdr.Flag.value_or(yaml::Hex16(XCOFF::SHR_SYMTAB)));520 if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64)521 W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64);522 } else {523 if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32)524 W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32);525 }526}527 528void XCOFFWriter::writeSectionHeaders() {529 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {530 XCOFFYAML::Section DerivedSec = InitSections[I];531 writeName(DerivedSec.SectionName, W);532 if (Is64Bit) {533 // Virtual address is the same as physical address.534 W.write<uint64_t>(DerivedSec.Address); // Physical address535 W.write<uint64_t>(DerivedSec.Address); // Virtual address536 W.write<uint64_t>(DerivedSec.Size);537 W.write<uint64_t>(DerivedSec.FileOffsetToData);538 W.write<uint64_t>(DerivedSec.FileOffsetToRelocations);539 W.write<uint64_t>(DerivedSec.FileOffsetToLineNumbers);540 W.write<uint32_t>(DerivedSec.NumberOfRelocations);541 W.write<uint32_t>(DerivedSec.NumberOfLineNumbers);542 W.write<int32_t>(DerivedSec.Flags);543 W.OS.write_zeros(4);544 } else {545 // Virtual address is the same as physical address.546 W.write<uint32_t>(DerivedSec.Address); // Physical address547 W.write<uint32_t>(DerivedSec.Address); // Virtual address548 W.write<uint32_t>(DerivedSec.Size);549 W.write<uint32_t>(DerivedSec.FileOffsetToData);550 W.write<uint32_t>(DerivedSec.FileOffsetToRelocations);551 W.write<uint32_t>(DerivedSec.FileOffsetToLineNumbers);552 W.write<uint16_t>(DerivedSec.NumberOfRelocations);553 W.write<uint16_t>(DerivedSec.NumberOfLineNumbers);554 W.write<int32_t>(DerivedSec.Flags);555 }556 }557}558 559bool XCOFFWriter::writeSectionData() {560 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {561 XCOFFYAML::Section YamlSec = Obj.Sections[I];562 if (YamlSec.SectionData.binary_size()) {563 // Fill the padding size with zeros.564 int64_t PaddingSize = (uint64_t)InitSections[I].FileOffsetToData -565 (W.OS.tell() - StartOffset);566 if (PaddingSize < 0) {567 ErrHandler("redundant data was written before section data");568 return false;569 }570 W.OS.write_zeros(PaddingSize);571 YamlSec.SectionData.writeAsBinary(W.OS);572 }573 }574 return true;575}576 577bool XCOFFWriter::writeRelocations() {578 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {579 XCOFFYAML::Section YamlSec = Obj.Sections[I];580 if (!YamlSec.Relocations.empty()) {581 int64_t PaddingSize =582 InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset);583 if (PaddingSize < 0) {584 ErrHandler("redundant data was written before relocations");585 return false;586 }587 W.OS.write_zeros(PaddingSize);588 for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) {589 if (Is64Bit)590 W.write<uint64_t>(YamlRel.VirtualAddress);591 else592 W.write<uint32_t>(YamlRel.VirtualAddress);593 W.write<uint32_t>(YamlRel.SymbolIndex);594 W.write<uint8_t>(YamlRel.Info);595 W.write<uint8_t>(YamlRel.Type);596 }597 }598 }599 return true;600}601 602bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym) {603 uint8_t SymAlignAndType = 0;604 if (AuxSym.SymbolAlignmentAndType) {605 if (AuxSym.SymbolType || AuxSym.SymbolAlignment) {606 ErrHandler("cannot specify SymbolType or SymbolAlignment if "607 "SymbolAlignmentAndType is specified");608 return false;609 }610 SymAlignAndType = *AuxSym.SymbolAlignmentAndType;611 } else {612 if (AuxSym.SymbolType) {613 uint8_t SymbolType = *AuxSym.SymbolType;614 if (SymbolType & ~XCOFFCsectAuxRef::SymbolTypeMask) {615 ErrHandler("symbol type must be less than " +616 Twine(1 + XCOFFCsectAuxRef::SymbolTypeMask));617 return false;618 }619 SymAlignAndType = SymbolType;620 }621 if (AuxSym.SymbolAlignment) {622 const uint8_t ShiftedSymbolAlignmentMask =623 XCOFFCsectAuxRef::SymbolAlignmentMask >>624 XCOFFCsectAuxRef::SymbolAlignmentBitOffset;625 626 if (*AuxSym.SymbolAlignment & ~ShiftedSymbolAlignmentMask) {627 ErrHandler("symbol alignment must be less than " +628 Twine(1 + ShiftedSymbolAlignmentMask));629 return false;630 }631 SymAlignAndType |= (*AuxSym.SymbolAlignment632 << XCOFFCsectAuxRef::SymbolAlignmentBitOffset);633 }634 }635 if (Is64Bit) {636 W.write<uint32_t>(AuxSym.SectionOrLengthLo.value_or(0));637 W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0));638 W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0));639 W.write<uint8_t>(SymAlignAndType);640 W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR));641 W.write<uint32_t>(AuxSym.SectionOrLengthHi.value_or(0));642 W.write<uint8_t>(0);643 W.write<uint8_t>(XCOFF::AUX_CSECT);644 } else {645 W.write<uint32_t>(AuxSym.SectionOrLength.value_or(0));646 W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0));647 W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0));648 W.write<uint8_t>(SymAlignAndType);649 W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR));650 W.write<uint32_t>(AuxSym.StabInfoIndex.value_or(0));651 W.write<uint16_t>(AuxSym.StabSectNum.value_or(0));652 }653 return true;654}655 656bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym) {657 assert(Is64Bit && "can't write the exception auxiliary symbol for XCOFF32");658 W.write<uint64_t>(AuxSym.OffsetToExceptionTbl.value_or(0));659 W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));660 W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));661 W.write<uint8_t>(0);662 W.write<uint8_t>(XCOFF::AUX_EXCEPT);663 return true;664}665 666bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym) {667 if (Is64Bit) {668 W.write<uint64_t>(AuxSym.PtrToLineNum.value_or(0));669 W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));670 W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));671 W.write<uint8_t>(0);672 W.write<uint8_t>(XCOFF::AUX_FCN);673 } else {674 W.write<uint32_t>(AuxSym.OffsetToExceptionTbl.value_or(0));675 W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));676 W.write<uint32_t>(AuxSym.PtrToLineNum.value_or(0));677 W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));678 W.OS.write_zeros(2);679 }680 return true;681}682 683bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym) {684 StringRef FileName = AuxSym.FileNameOrString.value_or("");685 if (nameShouldBeInStringTable(FileName)) {686 W.write<int32_t>(0);687 W.write<uint32_t>(StrTblBuilder.getOffset(FileName));688 } else {689 writeName(FileName, W);690 }691 W.OS.write_zeros(XCOFF::FileNamePadSize);692 W.write<uint8_t>(AuxSym.FileStringType.value_or(XCOFF::XFT_FN));693 if (Is64Bit) {694 W.OS.write_zeros(2);695 W.write<uint8_t>(XCOFF::AUX_FILE);696 } else {697 W.OS.write_zeros(3);698 }699 return true;700}701 702bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym) {703 if (Is64Bit) {704 W.write<uint32_t>(AuxSym.LineNum.value_or(0));705 W.OS.write_zeros(13);706 W.write<uint8_t>(XCOFF::AUX_SYM);707 } else {708 W.OS.write_zeros(2);709 W.write<uint16_t>(AuxSym.LineNumHi.value_or(0));710 W.write<uint16_t>(AuxSym.LineNumLo.value_or(0));711 W.OS.write_zeros(12);712 }713 return true;714}715 716bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym) {717 if (Is64Bit) {718 W.write<uint64_t>(AuxSym.LengthOfSectionPortion.value_or(0));719 W.write<uint64_t>(AuxSym.NumberOfRelocEnt.value_or(0));720 W.write<uint8_t>(0);721 W.write<uint8_t>(XCOFF::AUX_SECT);722 } else {723 W.write<uint32_t>(AuxSym.LengthOfSectionPortion.value_or(0));724 W.OS.write_zeros(4);725 W.write<uint32_t>(AuxSym.NumberOfRelocEnt.value_or(0));726 W.OS.write_zeros(6);727 }728 return true;729}730 731bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym) {732 assert(!Is64Bit && "can't write the stat auxiliary symbol for XCOFF64");733 W.write<uint32_t>(AuxSym.SectionLength.value_or(0));734 W.write<uint16_t>(AuxSym.NumberOfRelocEnt.value_or(0));735 W.write<uint16_t>(AuxSym.NumberOfLineNum.value_or(0));736 W.OS.write_zeros(10);737 return true;738}739 740bool XCOFFWriter::writeAuxSymbol(741 const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym) {742 if (auto AS = dyn_cast<XCOFFYAML::CsectAuxEnt>(AuxSym.get()))743 return writeAuxSymbol(*AS);744 else if (auto AS = dyn_cast<XCOFFYAML::FunctionAuxEnt>(AuxSym.get()))745 return writeAuxSymbol(*AS);746 else if (auto AS = dyn_cast<XCOFFYAML::ExcpetionAuxEnt>(AuxSym.get()))747 return writeAuxSymbol(*AS);748 else if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get()))749 return writeAuxSymbol(*AS);750 else if (auto AS = dyn_cast<XCOFFYAML::BlockAuxEnt>(AuxSym.get()))751 return writeAuxSymbol(*AS);752 else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForDWARF>(AuxSym.get()))753 return writeAuxSymbol(*AS);754 else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForStat>(AuxSym.get()))755 return writeAuxSymbol(*AS);756 llvm_unreachable("unknown auxiliary symbol type");757 return false;758}759 760bool XCOFFWriter::writeSymbols() {761 int64_t PaddingSize =762 InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset);763 if (PaddingSize < 0) {764 ErrHandler("redundant data was written before symbols");765 return false;766 }767 W.OS.write_zeros(PaddingSize);768 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {769 if (Is64Bit) {770 W.write<uint64_t>(YamlSym.Value);771 W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));772 } else {773 if (nameShouldBeInStringTable(YamlSym.SymbolName)) {774 // For XCOFF32: A value of 0 indicates that the symbol name is in the775 // string table.776 W.write<int32_t>(0);777 W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));778 } else {779 writeName(YamlSym.SymbolName, W);780 }781 W.write<uint32_t>(YamlSym.Value);782 }783 if (YamlSym.SectionName) {784 auto It = SectionIndexMap.find(*YamlSym.SectionName);785 if (It == SectionIndexMap.end()) {786 ErrHandler("the SectionName " + *YamlSym.SectionName +787 " specified in the symbol does not exist");788 return false;789 }790 if (YamlSym.SectionIndex && It->second != *YamlSym.SectionIndex) {791 ErrHandler("the SectionName " + *YamlSym.SectionName +792 " and the SectionIndex (" + Twine(*YamlSym.SectionIndex) +793 ") refer to different sections");794 return false;795 }796 W.write<int16_t>(It->second);797 } else {798 W.write<int16_t>(YamlSym.SectionIndex.value_or(0));799 }800 W.write<uint16_t>(YamlSym.Type);801 W.write<uint8_t>(YamlSym.StorageClass);802 803 uint8_t NumOfAuxSym = YamlSym.NumberOfAuxEntries.value_or(0);804 W.write<uint8_t>(NumOfAuxSym);805 806 if (!NumOfAuxSym && !YamlSym.AuxEntries.size())807 continue;808 809 // Now write auxiliary entries.810 if (!YamlSym.AuxEntries.size()) {811 W.OS.write_zeros(XCOFF::SymbolTableEntrySize * NumOfAuxSym);812 } else {813 for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym :814 YamlSym.AuxEntries) {815 if (!writeAuxSymbol(AuxSym))816 return false;817 }818 // Pad with zeros.819 if (NumOfAuxSym > YamlSym.AuxEntries.size())820 W.OS.write_zeros(XCOFF::SymbolTableEntrySize *821 (NumOfAuxSym - YamlSym.AuxEntries.size()));822 }823 }824 return true;825}826 827void XCOFFWriter::writeStringTable() {828 if (Obj.StrTbl.RawContent) {829 Obj.StrTbl.RawContent->writeAsBinary(W.OS);830 if (Obj.StrTbl.ContentSize) {831 assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() &&832 "Specified ContentSize is less than the RawContent size.");833 W.OS.write_zeros(*Obj.StrTbl.ContentSize -834 Obj.StrTbl.RawContent->binary_size());835 }836 return;837 }838 839 size_t StrTblBuilderSize = StrTblBuilder.getSize();840 // If neither Length nor ContentSize is specified, write the StrTblBuilder841 // directly, which contains the auto-generated Length value.842 if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) {843 if (StrTblBuilderSize <= 4)844 return;845 StrTblBuilder.write(W.OS);846 return;847 }848 849 // Serialize the string table's content to a temporary buffer.850 std::unique_ptr<WritableMemoryBuffer> Buf =851 WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize);852 uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart());853 StrTblBuilder.write(Ptr);854 // Replace the first 4 bytes, which contain the auto-generated Length value,855 // with the specified value.856 memset(Ptr, 0, 4);857 support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length858 : *Obj.StrTbl.ContentSize);859 // Copy the buffer content to the actual output stream.860 W.OS.write(Buf->getBufferStart(), Buf->getBufferSize());861 // Add zeros as padding after strings.862 if (Obj.StrTbl.ContentSize) {863 assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize &&864 "Specified ContentSize is less than the StringTableBuilder size.");865 W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize);866 }867}868 869bool XCOFFWriter::writeXCOFF() {870 if (!assignAddressesAndIndices())871 return false;872 StartOffset = W.OS.tell();873 writeFileHeader();874 if (InitFileHdr.AuxHeaderSize)875 writeAuxFileHeader();876 if (!Obj.Sections.empty()) {877 writeSectionHeaders();878 if (!writeSectionData())879 return false;880 if (!writeRelocations())881 return false;882 }883 if (!Obj.Symbols.empty() && !writeSymbols())884 return false;885 writeStringTable();886 return true;887}888 889} // end anonymous namespace890 891namespace llvm {892namespace yaml {893 894bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) {895 XCOFFWriter Writer(Doc, Out, EH);896 return Writer.writeXCOFF();897}898 899} // namespace yaml900} // namespace llvm901