Path: blob/main/contrib/llvm-project/llvm/lib/ObjectYAML/XCOFFEmitter.cpp
35234 views
//===- yaml2xcoff - Convert YAML to a xcoff object file -------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// The xcoff component of yaml2obj.10///11//===----------------------------------------------------------------------===//1213#include "llvm/ADT/DenseMap.h"14#include "llvm/BinaryFormat/XCOFF.h"15#include "llvm/MC/StringTableBuilder.h"16#include "llvm/Object/XCOFFObjectFile.h"17#include "llvm/ObjectYAML/ObjectYAML.h"18#include "llvm/ObjectYAML/yaml2obj.h"19#include "llvm/Support/EndianStream.h"20#include "llvm/Support/LEB128.h"21#include "llvm/Support/MemoryBuffer.h"22#include "llvm/Support/raw_ostream.h"2324using namespace llvm;25using namespace llvm::object;2627namespace {2829constexpr unsigned DefaultSectionAlign = 4;30constexpr int16_t MaxSectionIndex = INT16_MAX;31constexpr uint32_t MaxRawDataSize = UINT32_MAX;3233class XCOFFWriter {34public:35XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH)36: Obj(Obj), W(OS, llvm::endianness::big), ErrHandler(EH),37StrTblBuilder(StringTableBuilder::XCOFF) {38Is64Bit = Obj.Header.Magic == (llvm::yaml::Hex16)XCOFF::XCOFF64;39}40bool writeXCOFF();4142private:43void reportOverwrite(uint64_t currentOffset, uint64_t specifiedOffset,44const Twine &fieldName);45bool nameShouldBeInStringTable(StringRef SymbolName);46bool initFileHeader(uint64_t CurrentOffset);47void initAuxFileHeader();48bool initSectionHeaders(uint64_t &CurrentOffset);49bool initRelocations(uint64_t &CurrentOffset);50bool initStringTable();51bool assignAddressesAndIndices();5253void writeFileHeader();54void writeAuxFileHeader();55void writeSectionHeaders();56bool writeSectionData();57bool writeRelocations();58bool writeSymbols();59void writeStringTable();6061bool writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym);62bool writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym);63bool writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym);64bool writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym);65bool writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym);66bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym);67bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym);68bool writeAuxSymbol(const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym);6970XCOFFYAML::Object &Obj;71bool Is64Bit = false;72support::endian::Writer W;73yaml::ErrorHandler ErrHandler;74StringTableBuilder StrTblBuilder;75uint64_t StartOffset = 0u;76// Map the section name to its corrresponding section index.77DenseMap<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}};81XCOFFYAML::FileHeader InitFileHdr = Obj.Header;82XCOFFYAML::AuxiliaryHeader InitAuxFileHdr;83std::vector<XCOFFYAML::Section> InitSections = Obj.Sections;84};8586static void writeName(StringRef StrName, support::endian::Writer W) {87char Name[XCOFF::NameSize];88memset(Name, 0, XCOFF::NameSize);89char SrcName[] = "";90memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size());91ArrayRef<char> NameRef(Name, XCOFF::NameSize);92W.write(NameRef);93}9495void XCOFFWriter::reportOverwrite(uint64_t CurrentOffset,96uint64_t specifiedOffset,97const Twine &fieldName) {98ErrHandler("current file offset (" + Twine(CurrentOffset) +99") is bigger than the specified " + fieldName + " (" +100Twine(specifiedOffset) + ") ");101}102103bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) {104// For XCOFF64: The symbol name is always in the string table.105return (SymbolName.size() > XCOFF::NameSize) || Is64Bit;106}107108bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) {109for (XCOFFYAML::Section &InitSection : InitSections) {110if (!InitSection.Relocations.empty()) {111uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64112: XCOFF::RelocationSerializationSize32;113uint64_t UsedSize = RelSize * InitSection.Relocations.size();114115// If NumberOfRelocations was specified, we use it, even if it's116// not consistent with the number of provided relocations.117if (!InitSection.NumberOfRelocations)118InitSection.NumberOfRelocations = InitSection.Relocations.size();119120// If the YAML file specified an offset to relocations, we use it.121if (InitSection.FileOffsetToRelocations) {122if (CurrentOffset > InitSection.FileOffsetToRelocations) {123reportOverwrite(CurrentOffset, InitSection.FileOffsetToRelocations,124"FileOffsetToRelocations for the " +125InitSection.SectionName + " section");126return false;127}128CurrentOffset = InitSection.FileOffsetToRelocations;129} else130InitSection.FileOffsetToRelocations = CurrentOffset;131CurrentOffset += UsedSize;132if (CurrentOffset > MaxRawDataSize) {133ErrHandler("maximum object size (" + Twine(MaxRawDataSize) +134") exceeded when writing relocation data for section " +135Twine(InitSection.SectionName));136return false;137}138}139}140return true;141}142143bool XCOFFWriter::initSectionHeaders(uint64_t &CurrentOffset) {144uint64_t CurrentEndDataAddr = 0;145uint64_t CurrentEndTDataAddr = 0;146for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {147// Assign indices for sections.148if (InitSections[I].SectionName.size() &&149!SectionIndexMap[InitSections[I].SectionName]) {150// The section index starts from 1.151SectionIndexMap[InitSections[I].SectionName] = I + 1;152if ((I + 1) > MaxSectionIndex) {153ErrHandler("exceeded the maximum permitted section index of " +154Twine(MaxSectionIndex));155return false;156}157}158159if (!InitSections[I].Size)160InitSections[I].Size = InitSections[I].SectionData.binary_size();161162// Section data addresses (physical/virtual) are related to symbol163// addresses and alignments. Furthermore, it is possible to specify the164// same starting addresses for the .text, .data, and .tdata sections.165// Without examining all the symbols and their addreses and alignments,166// it is not possible to compute valid section addresses. The only167// condition required by XCOFF is that the .bss section immediately168// follows the .data section, and the .tbss section immediately follows169// the .tdata section. Therefore, we only assign addresses to the .bss170// and .tbss sections if they do not already have non-zero addresses.171// (If the YAML file is being used to generate a valid object file, we172// expect all section addresses to be specified explicitly.)173switch (InitSections[I].Flags) {174case XCOFF::STYP_DATA:175CurrentEndDataAddr = InitSections[I].Address + InitSections[I].Size;176break;177case XCOFF::STYP_BSS:178if (!InitSections[I].Address)179InitSections[I].Address = CurrentEndDataAddr;180break;181case XCOFF::STYP_TDATA:182CurrentEndTDataAddr = InitSections[I].Address + InitSections[I].Size;183break;184case XCOFF::STYP_TBSS:185if (!InitSections[I].Address)186InitSections[I].Address = CurrentEndTDataAddr;187break;188}189190if (InitSections[I].SectionData.binary_size()) {191if (InitSections[I].FileOffsetToData) {192// Use the providedFileOffsetToData.193if (CurrentOffset > InitSections[I].FileOffsetToData) {194reportOverwrite(CurrentOffset, InitSections[I].FileOffsetToData,195"FileOffsetToData for the " +196InitSections[I].SectionName + " section");197return false;198}199CurrentOffset = InitSections[I].FileOffsetToData;200} else {201CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign);202InitSections[I].FileOffsetToData = CurrentOffset;203}204CurrentOffset += InitSections[I].SectionData.binary_size();205if (CurrentOffset > MaxRawDataSize) {206ErrHandler("maximum object size (" + Twine(MaxRawDataSize) +207") exceeded when writing data for section " + Twine(I + 1) +208" (" + Twine(InitSections[I].SectionName) + ")");209return false;210}211}212if (InitSections[I].SectionSubtype) {213uint32_t DWARFSubtype =214static_cast<uint32_t>(*InitSections[I].SectionSubtype);215if (InitSections[I].Flags != XCOFF::STYP_DWARF) {216ErrHandler("a DWARFSectionSubtype is only allowed for a DWARF section");217return false;218}219unsigned Mask = Is64Bit ? XCOFFSectionHeader64::SectionFlagsTypeMask220: XCOFFSectionHeader32::SectionFlagsTypeMask;221if (DWARFSubtype & Mask) {222ErrHandler("the low-order bits of DWARFSectionSubtype must be 0");223return false;224}225InitSections[I].Flags |= DWARFSubtype;226}227}228return initRelocations(CurrentOffset);229}230231bool XCOFFWriter::initStringTable() {232if (Obj.StrTbl.RawContent) {233size_t RawSize = Obj.StrTbl.RawContent->binary_size();234if (Obj.StrTbl.Strings || Obj.StrTbl.Length) {235ErrHandler(236"can't specify Strings or Length when RawContent is specified");237return false;238}239if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) {240ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +241") is less than the RawContent data size (" + Twine(RawSize) +242")");243return false;244}245return true;246}247if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) {248ErrHandler("ContentSize shouldn't be less than 4 without RawContent");249return false;250}251252// Build the string table.253StrTblBuilder.clear();254255if (Obj.StrTbl.Strings) {256// Add all specified strings to the string table.257for (StringRef StringEnt : *Obj.StrTbl.Strings)258StrTblBuilder.add(StringEnt);259260size_t StrTblIdx = 0;261size_t NumOfStrings = Obj.StrTbl.Strings->size();262for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {263if (nameShouldBeInStringTable(YamlSym.SymbolName)) {264if (StrTblIdx < NumOfStrings) {265// Overwrite the symbol name with the specified string.266YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx];267++StrTblIdx;268} else269// Names that are not overwritten are still stored in the string270// table.271StrTblBuilder.add(YamlSym.SymbolName);272}273}274} else {275for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {276if (nameShouldBeInStringTable(YamlSym.SymbolName))277StrTblBuilder.add(YamlSym.SymbolName);278}279}280281// Check if the file name in the File Auxiliary Entry should be added to the282// string table.283for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {284for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym :285YamlSym.AuxEntries) {286if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get()))287if (nameShouldBeInStringTable(AS->FileNameOrString.value_or("")))288StrTblBuilder.add(AS->FileNameOrString.value_or(""));289}290}291292StrTblBuilder.finalize();293294size_t StrTblSize = StrTblBuilder.getSize();295if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) {296ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +297") is less than the size of the data that would otherwise be "298"written (" +299Twine(StrTblSize) + ")");300return false;301}302303return true;304}305306bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) {307// The default format of the object file is XCOFF32.308InitFileHdr.Magic = XCOFF::XCOFF32;309InitFileHdr.NumberOfSections = Obj.Sections.size();310InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size();311312for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {313uint32_t AuxCount = YamlSym.AuxEntries.size();314if (YamlSym.NumberOfAuxEntries && *YamlSym.NumberOfAuxEntries < AuxCount) {315ErrHandler("specified NumberOfAuxEntries " +316Twine(static_cast<uint32_t>(*YamlSym.NumberOfAuxEntries)) +317" is less than the actual number "318"of auxiliary entries " +319Twine(AuxCount));320return false;321}322YamlSym.NumberOfAuxEntries = YamlSym.NumberOfAuxEntries.value_or(AuxCount);323// Add the number of auxiliary symbols to the total number.324InitFileHdr.NumberOfSymTableEntries += *YamlSym.NumberOfAuxEntries;325}326327// Calculate SymbolTableOffset for the file header.328if (InitFileHdr.NumberOfSymTableEntries) {329if (Obj.Header.SymbolTableOffset) {330if (CurrentOffset > Obj.Header.SymbolTableOffset) {331reportOverwrite(CurrentOffset, Obj.Header.SymbolTableOffset,332"SymbolTableOffset");333return false;334}335CurrentOffset = Obj.Header.SymbolTableOffset;336}337InitFileHdr.SymbolTableOffset = CurrentOffset;338CurrentOffset +=339InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize;340if (CurrentOffset > MaxRawDataSize) {341ErrHandler("maximum object size of " + Twine(MaxRawDataSize) +342" exceeded when writing symbols");343return false;344}345}346// TODO: Calculate FileOffsetToLineNumbers when line number supported.347return true;348}349350void XCOFFWriter::initAuxFileHeader() {351if (Obj.AuxHeader)352InitAuxFileHdr = *Obj.AuxHeader;353// In general, an object file might contain multiple sections of a given type,354// but in a loadable module, there must be exactly one .text, .data, .bss, and355// .loader section. A loadable object might also have one .tdata section and356// one .tbss section.357// Set these section-related values if not set explicitly. We assume that the358// input YAML matches the format of the loadable object, but if multiple input359// sections still have the same type, the first section with that type360// prevails.361for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {362switch (InitSections[I].Flags) {363case XCOFF::STYP_TEXT:364if (!InitAuxFileHdr.TextSize)365InitAuxFileHdr.TextSize = InitSections[I].Size;366if (!InitAuxFileHdr.TextStartAddr)367InitAuxFileHdr.TextStartAddr = InitSections[I].Address;368if (!InitAuxFileHdr.SecNumOfText)369InitAuxFileHdr.SecNumOfText = I + 1;370break;371case XCOFF::STYP_DATA:372if (!InitAuxFileHdr.InitDataSize)373InitAuxFileHdr.InitDataSize = InitSections[I].Size;374if (!InitAuxFileHdr.DataStartAddr)375InitAuxFileHdr.DataStartAddr = InitSections[I].Address;376if (!InitAuxFileHdr.SecNumOfData)377InitAuxFileHdr.SecNumOfData = I + 1;378break;379case XCOFF::STYP_BSS:380if (!InitAuxFileHdr.BssDataSize)381InitAuxFileHdr.BssDataSize = InitSections[I].Size;382if (!InitAuxFileHdr.SecNumOfBSS)383InitAuxFileHdr.SecNumOfBSS = I + 1;384break;385case XCOFF::STYP_TDATA:386if (!InitAuxFileHdr.SecNumOfTData)387InitAuxFileHdr.SecNumOfTData = I + 1;388break;389case XCOFF::STYP_TBSS:390if (!InitAuxFileHdr.SecNumOfTBSS)391InitAuxFileHdr.SecNumOfTBSS = I + 1;392break;393case XCOFF::STYP_LOADER:394if (!InitAuxFileHdr.SecNumOfLoader)395InitAuxFileHdr.SecNumOfLoader = I + 1;396break;397default:398break;399}400}401}402403bool XCOFFWriter::assignAddressesAndIndices() {404uint64_t FileHdrSize =405Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32;406407// If AuxHeaderSize is specified in the YAML file, we construct408// an auxiliary header.409uint64_t AuxFileHdrSize = 0;410411if (Obj.Header.AuxHeaderSize)412AuxFileHdrSize = Obj.Header.AuxHeaderSize;413else if (Obj.AuxHeader)414AuxFileHdrSize =415(Is64Bit ? XCOFF::AuxFileHeaderSize64 : XCOFF::AuxFileHeaderSize32);416uint64_t SecHdrSize =417Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32;418uint64_t CurrentOffset =419FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize;420421// Calculate section header info.422if (!initSectionHeaders(CurrentOffset))423return false;424425// Calculate file header info.426if (!initFileHeader(CurrentOffset))427return false;428InitFileHdr.AuxHeaderSize = AuxFileHdrSize;429430// Initialize the auxiliary file header.431if (AuxFileHdrSize)432initAuxFileHeader();433434// Initialize the string table.435return initStringTable();436}437438void XCOFFWriter::writeFileHeader() {439W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic);440W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections441: InitFileHdr.NumberOfSections);442W.write<int32_t>(Obj.Header.TimeStamp);443if (Is64Bit) {444W.write<uint64_t>(InitFileHdr.SymbolTableOffset);445W.write<uint16_t>(InitFileHdr.AuxHeaderSize);446W.write<uint16_t>(Obj.Header.Flags);447W.write<int32_t>(Obj.Header.NumberOfSymTableEntries448? Obj.Header.NumberOfSymTableEntries449: InitFileHdr.NumberOfSymTableEntries);450} else {451W.write<uint32_t>(InitFileHdr.SymbolTableOffset);452W.write<int32_t>(Obj.Header.NumberOfSymTableEntries453? Obj.Header.NumberOfSymTableEntries454: InitFileHdr.NumberOfSymTableEntries);455W.write<uint16_t>(InitFileHdr.AuxHeaderSize);456W.write<uint16_t>(Obj.Header.Flags);457}458}459460void XCOFFWriter::writeAuxFileHeader() {461W.write<uint16_t>(InitAuxFileHdr.Magic.value_or(yaml::Hex16(1)));462W.write<uint16_t>(InitAuxFileHdr.Version.value_or(yaml::Hex16(1)));463if (Is64Bit) {464W.OS.write_zeros(4); // Reserved for debugger.465W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0)));466W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0)));467W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0)));468} else {469W.write<uint32_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0)));470W.write<uint32_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0)));471W.write<uint32_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0)));472W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0)));473W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0)));474W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0)));475// A short 32-bit auxiliary header ends here.476if (InitFileHdr.AuxHeaderSize == XCOFF::AuxFileHeaderSizeShort)477return;478W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0)));479}480W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.value_or(0));481W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.value_or(0));482W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.value_or(0));483W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.value_or(0));484W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.value_or(0));485W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.value_or(0));486W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.value_or(yaml::Hex16(0)));487W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.value_or(yaml::Hex16(0)));488W.write<uint16_t>(InitAuxFileHdr.ModuleType.value_or(yaml::Hex16(0)));489W.write<uint8_t>(InitAuxFileHdr.CpuFlag.value_or(yaml::Hex8(0)));490W.write<uint8_t>(0); // Reserved for CPU type.491if (Is64Bit) {492W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0)));493W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0)));494W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0)));495W.write<uint8_t>(496InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0x80)));497W.write<uint64_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0)));498W.write<uint64_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0)));499W.write<uint64_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0)));500W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0)));501W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0)));502W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0)));503} else {504W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0)));505W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0)));506W.OS.write_zeros(4); // Reserved for debugger.507W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0)));508W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0)));509W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0)));510W.write<uint8_t>(511InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0)));512}513W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.value_or(0));514W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.value_or(0));515if (Is64Bit) {516W.write<uint16_t>(517InitAuxFileHdr.Flag.value_or(yaml::Hex16(XCOFF::SHR_SYMTAB)));518if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64)519W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64);520} else {521if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32)522W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32);523}524}525526void XCOFFWriter::writeSectionHeaders() {527for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {528XCOFFYAML::Section DerivedSec = InitSections[I];529writeName(DerivedSec.SectionName, W);530if (Is64Bit) {531// Virtual address is the same as physical address.532W.write<uint64_t>(DerivedSec.Address); // Physical address533W.write<uint64_t>(DerivedSec.Address); // Virtual address534W.write<uint64_t>(DerivedSec.Size);535W.write<uint64_t>(DerivedSec.FileOffsetToData);536W.write<uint64_t>(DerivedSec.FileOffsetToRelocations);537W.write<uint64_t>(DerivedSec.FileOffsetToLineNumbers);538W.write<uint32_t>(DerivedSec.NumberOfRelocations);539W.write<uint32_t>(DerivedSec.NumberOfLineNumbers);540W.write<int32_t>(DerivedSec.Flags);541W.OS.write_zeros(4);542} else {543// Virtual address is the same as physical address.544W.write<uint32_t>(DerivedSec.Address); // Physical address545W.write<uint32_t>(DerivedSec.Address); // Virtual address546W.write<uint32_t>(DerivedSec.Size);547W.write<uint32_t>(DerivedSec.FileOffsetToData);548W.write<uint32_t>(DerivedSec.FileOffsetToRelocations);549W.write<uint32_t>(DerivedSec.FileOffsetToLineNumbers);550W.write<uint16_t>(DerivedSec.NumberOfRelocations);551W.write<uint16_t>(DerivedSec.NumberOfLineNumbers);552W.write<int32_t>(DerivedSec.Flags);553}554}555}556557bool XCOFFWriter::writeSectionData() {558for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {559XCOFFYAML::Section YamlSec = Obj.Sections[I];560if (YamlSec.SectionData.binary_size()) {561// Fill the padding size with zeros.562int64_t PaddingSize = (uint64_t)InitSections[I].FileOffsetToData -563(W.OS.tell() - StartOffset);564if (PaddingSize < 0) {565ErrHandler("redundant data was written before section data");566return false;567}568W.OS.write_zeros(PaddingSize);569YamlSec.SectionData.writeAsBinary(W.OS);570}571}572return true;573}574575bool XCOFFWriter::writeRelocations() {576for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {577XCOFFYAML::Section YamlSec = Obj.Sections[I];578if (!YamlSec.Relocations.empty()) {579int64_t PaddingSize =580InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset);581if (PaddingSize < 0) {582ErrHandler("redundant data was written before relocations");583return false;584}585W.OS.write_zeros(PaddingSize);586for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) {587if (Is64Bit)588W.write<uint64_t>(YamlRel.VirtualAddress);589else590W.write<uint32_t>(YamlRel.VirtualAddress);591W.write<uint32_t>(YamlRel.SymbolIndex);592W.write<uint8_t>(YamlRel.Info);593W.write<uint8_t>(YamlRel.Type);594}595}596}597return true;598}599600bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym) {601uint8_t SymAlignAndType = 0;602if (AuxSym.SymbolAlignmentAndType) {603if (AuxSym.SymbolType || AuxSym.SymbolAlignment) {604ErrHandler("cannot specify SymbolType or SymbolAlignment if "605"SymbolAlignmentAndType is specified");606return false;607}608SymAlignAndType = *AuxSym.SymbolAlignmentAndType;609} else {610if (AuxSym.SymbolType) {611uint8_t SymbolType = *AuxSym.SymbolType;612if (SymbolType & ~XCOFFCsectAuxRef::SymbolTypeMask) {613ErrHandler("symbol type must be less than " +614Twine(1 + XCOFFCsectAuxRef::SymbolTypeMask));615return false;616}617SymAlignAndType = SymbolType;618}619if (AuxSym.SymbolAlignment) {620const uint8_t ShiftedSymbolAlignmentMask =621XCOFFCsectAuxRef::SymbolAlignmentMask >>622XCOFFCsectAuxRef::SymbolAlignmentBitOffset;623624if (*AuxSym.SymbolAlignment & ~ShiftedSymbolAlignmentMask) {625ErrHandler("symbol alignment must be less than " +626Twine(1 + ShiftedSymbolAlignmentMask));627return false;628}629SymAlignAndType |= (*AuxSym.SymbolAlignment630<< XCOFFCsectAuxRef::SymbolAlignmentBitOffset);631}632}633if (Is64Bit) {634W.write<uint32_t>(AuxSym.SectionOrLengthLo.value_or(0));635W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0));636W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0));637W.write<uint8_t>(SymAlignAndType);638W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR));639W.write<uint32_t>(AuxSym.SectionOrLengthHi.value_or(0));640W.write<uint8_t>(0);641W.write<uint8_t>(XCOFF::AUX_CSECT);642} else {643W.write<uint32_t>(AuxSym.SectionOrLength.value_or(0));644W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0));645W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0));646W.write<uint8_t>(SymAlignAndType);647W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR));648W.write<uint32_t>(AuxSym.StabInfoIndex.value_or(0));649W.write<uint16_t>(AuxSym.StabSectNum.value_or(0));650}651return true;652}653654bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym) {655assert(Is64Bit && "can't write the exception auxiliary symbol for XCOFF32");656W.write<uint64_t>(AuxSym.OffsetToExceptionTbl.value_or(0));657W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));658W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));659W.write<uint8_t>(0);660W.write<uint8_t>(XCOFF::AUX_EXCEPT);661return true;662}663664bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym) {665if (Is64Bit) {666W.write<uint64_t>(AuxSym.PtrToLineNum.value_or(0));667W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));668W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));669W.write<uint8_t>(0);670W.write<uint8_t>(XCOFF::AUX_FCN);671} else {672W.write<uint32_t>(AuxSym.OffsetToExceptionTbl.value_or(0));673W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));674W.write<uint32_t>(AuxSym.PtrToLineNum.value_or(0));675W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));676W.OS.write_zeros(2);677}678return true;679}680681bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym) {682StringRef FileName = AuxSym.FileNameOrString.value_or("");683if (nameShouldBeInStringTable(FileName)) {684W.write<int32_t>(0);685W.write<uint32_t>(StrTblBuilder.getOffset(FileName));686} else {687writeName(FileName, W);688}689W.OS.write_zeros(XCOFF::FileNamePadSize);690W.write<uint8_t>(AuxSym.FileStringType.value_or(XCOFF::XFT_FN));691if (Is64Bit) {692W.OS.write_zeros(2);693W.write<uint8_t>(XCOFF::AUX_FILE);694} else {695W.OS.write_zeros(3);696}697return true;698}699700bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym) {701if (Is64Bit) {702W.write<uint32_t>(AuxSym.LineNum.value_or(0));703W.OS.write_zeros(13);704W.write<uint8_t>(XCOFF::AUX_SYM);705} else {706W.OS.write_zeros(2);707W.write<uint16_t>(AuxSym.LineNumHi.value_or(0));708W.write<uint16_t>(AuxSym.LineNumLo.value_or(0));709W.OS.write_zeros(12);710}711return true;712}713714bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym) {715if (Is64Bit) {716W.write<uint64_t>(AuxSym.LengthOfSectionPortion.value_or(0));717W.write<uint64_t>(AuxSym.NumberOfRelocEnt.value_or(0));718W.write<uint8_t>(0);719W.write<uint8_t>(XCOFF::AUX_SECT);720} else {721W.write<uint32_t>(AuxSym.LengthOfSectionPortion.value_or(0));722W.OS.write_zeros(4);723W.write<uint32_t>(AuxSym.NumberOfRelocEnt.value_or(0));724W.OS.write_zeros(6);725}726return true;727}728729bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym) {730assert(!Is64Bit && "can't write the stat auxiliary symbol for XCOFF64");731W.write<uint32_t>(AuxSym.SectionLength.value_or(0));732W.write<uint16_t>(AuxSym.NumberOfRelocEnt.value_or(0));733W.write<uint16_t>(AuxSym.NumberOfLineNum.value_or(0));734W.OS.write_zeros(10);735return true;736}737738bool XCOFFWriter::writeAuxSymbol(739const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym) {740if (auto AS = dyn_cast<XCOFFYAML::CsectAuxEnt>(AuxSym.get()))741return writeAuxSymbol(*AS);742else if (auto AS = dyn_cast<XCOFFYAML::FunctionAuxEnt>(AuxSym.get()))743return writeAuxSymbol(*AS);744else if (auto AS = dyn_cast<XCOFFYAML::ExcpetionAuxEnt>(AuxSym.get()))745return writeAuxSymbol(*AS);746else if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get()))747return writeAuxSymbol(*AS);748else if (auto AS = dyn_cast<XCOFFYAML::BlockAuxEnt>(AuxSym.get()))749return writeAuxSymbol(*AS);750else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForDWARF>(AuxSym.get()))751return writeAuxSymbol(*AS);752else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForStat>(AuxSym.get()))753return writeAuxSymbol(*AS);754llvm_unreachable("unknown auxiliary symbol type");755return false;756}757758bool XCOFFWriter::writeSymbols() {759int64_t PaddingSize =760InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset);761if (PaddingSize < 0) {762ErrHandler("redundant data was written before symbols");763return false;764}765W.OS.write_zeros(PaddingSize);766for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {767if (Is64Bit) {768W.write<uint64_t>(YamlSym.Value);769W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));770} else {771if (nameShouldBeInStringTable(YamlSym.SymbolName)) {772// For XCOFF32: A value of 0 indicates that the symbol name is in the773// string table.774W.write<int32_t>(0);775W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));776} else {777writeName(YamlSym.SymbolName, W);778}779W.write<uint32_t>(YamlSym.Value);780}781if (YamlSym.SectionName) {782if (!SectionIndexMap.count(*YamlSym.SectionName)) {783ErrHandler("the SectionName " + *YamlSym.SectionName +784" specified in the symbol does not exist");785return false;786}787if (YamlSym.SectionIndex &&788SectionIndexMap[*YamlSym.SectionName] != *YamlSym.SectionIndex) {789ErrHandler("the SectionName " + *YamlSym.SectionName +790" and the SectionIndex (" + Twine(*YamlSym.SectionIndex) +791") refer to different sections");792return false;793}794W.write<int16_t>(SectionIndexMap[*YamlSym.SectionName]);795} else {796W.write<int16_t>(YamlSym.SectionIndex ? *YamlSym.SectionIndex : 0);797}798W.write<uint16_t>(YamlSym.Type);799W.write<uint8_t>(YamlSym.StorageClass);800801uint8_t NumOfAuxSym = YamlSym.NumberOfAuxEntries.value_or(0);802W.write<uint8_t>(NumOfAuxSym);803804if (!NumOfAuxSym && !YamlSym.AuxEntries.size())805continue;806807// Now write auxiliary entries.808if (!YamlSym.AuxEntries.size()) {809W.OS.write_zeros(XCOFF::SymbolTableEntrySize * NumOfAuxSym);810} else {811for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym :812YamlSym.AuxEntries) {813if (!writeAuxSymbol(AuxSym))814return false;815}816// Pad with zeros.817if (NumOfAuxSym > YamlSym.AuxEntries.size())818W.OS.write_zeros(XCOFF::SymbolTableEntrySize *819(NumOfAuxSym - YamlSym.AuxEntries.size()));820}821}822return true;823}824825void XCOFFWriter::writeStringTable() {826if (Obj.StrTbl.RawContent) {827Obj.StrTbl.RawContent->writeAsBinary(W.OS);828if (Obj.StrTbl.ContentSize) {829assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() &&830"Specified ContentSize is less than the RawContent size.");831W.OS.write_zeros(*Obj.StrTbl.ContentSize -832Obj.StrTbl.RawContent->binary_size());833}834return;835}836837size_t StrTblBuilderSize = StrTblBuilder.getSize();838// If neither Length nor ContentSize is specified, write the StrTblBuilder839// directly, which contains the auto-generated Length value.840if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) {841if (StrTblBuilderSize <= 4)842return;843StrTblBuilder.write(W.OS);844return;845}846847// Serialize the string table's content to a temporary buffer.848std::unique_ptr<WritableMemoryBuffer> Buf =849WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize);850uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart());851StrTblBuilder.write(Ptr);852// Replace the first 4 bytes, which contain the auto-generated Length value,853// with the specified value.854memset(Ptr, 0, 4);855support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length856: *Obj.StrTbl.ContentSize);857// Copy the buffer content to the actual output stream.858W.OS.write(Buf->getBufferStart(), Buf->getBufferSize());859// Add zeros as padding after strings.860if (Obj.StrTbl.ContentSize) {861assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize &&862"Specified ContentSize is less than the StringTableBuilder size.");863W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize);864}865}866867bool XCOFFWriter::writeXCOFF() {868if (!assignAddressesAndIndices())869return false;870StartOffset = W.OS.tell();871writeFileHeader();872if (InitFileHdr.AuxHeaderSize)873writeAuxFileHeader();874if (!Obj.Sections.empty()) {875writeSectionHeaders();876if (!writeSectionData())877return false;878if (!writeRelocations())879return false;880}881if (!Obj.Symbols.empty() && !writeSymbols())882return false;883writeStringTable();884return true;885}886887} // end anonymous namespace888889namespace llvm {890namespace yaml {891892bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) {893XCOFFWriter Writer(Doc, Out, EH);894return Writer.writeXCOFF();895}896897} // namespace yaml898} // namespace llvm899900901