From 78207e1f234eede120beaf730dfb7bb9d4e00a1b Mon Sep 17 00:00:00 2001 From: jasonliu Date: Thu, 24 Oct 2019 15:19:12 +0000 Subject: [PATCH] [NFC][XCOFF][AIX] Serialize object file writing for each CsectGroup Summary: Right now we handle each CsectGroup(ProgramCodeCsects, BSSCsects) individually when assigning indices, writing symbol table, and writing section raw data. However, there is already a pattern there, and we could common up those actions for every CsectGroup. This will make adding new CsectGroup(Read Write data, Read only data, TC/TOC, mergeable string) easier, and less error prone. Reviewed by: sfertile, daltenty, DiggerLin Approved by: daltenty Differential Revision: https://reviews.llvm.org/D69112 --- llvm/lib/MC/XCOFFObjectWriter.cpp | 294 +++++++++++++++++------------- 1 file changed, 164 insertions(+), 130 deletions(-) diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp index 353c21068735..2868972f71ce 100644 --- a/llvm/lib/MC/XCOFFObjectWriter.cpp +++ b/llvm/lib/MC/XCOFFObjectWriter.cpp @@ -44,6 +44,7 @@ using namespace llvm; namespace { constexpr unsigned DefaultSectionAlign = 4; +constexpr int16_t MaxSectionIndex = INT16_MAX; // Packs the csect's alignment and type into a byte. uint8_t getEncodedType(const MCSectionXCOFF *); @@ -73,6 +74,22 @@ struct ControlSection { : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1), Size(0) {} }; +// Type to be used for a container representing a set of csects with +// (approximately) the same storage mapping class. For example all the csects +// with a storage mapping class of `xmc_pr` will get placed into the same +// container. +struct CsectGroup { + enum LabelDefinitionSupport : bool { + LabelDefSupported = true, + LabelDefUnsupported = false + }; + + const LabelDefinitionSupport SupportLabelDef; + std::deque Csects; +}; + +using CsectGroups = std::deque; + // Represents the data related to a section excluding the csects that make up // the raw data of the section. The csects are stored separately as not all // sections contain csects, and some sections contain csects which are better @@ -94,49 +111,63 @@ struct Section { // Virtual sections do not need storage allocated in the object file. const bool IsVirtual; + // XCOFF has special section numbers for symbols: + // -2 Specifies N_DEBUG, a special symbolic debugging symbol. + // -1 Specifies N_ABS, an absolute symbol. The symbol has a value but is not + // relocatable. + // 0 Specifies N_UNDEF, an undefined external symbol. + // Therefore, we choose -3 (N_DEBUG - 1) to represent a section index that + // hasn't been initialized. + static constexpr int16_t UninitializedIndex = + XCOFF::ReservedSectionNum::N_DEBUG - 1; + + CsectGroups Groups; + void reset() { Address = 0; Size = 0; FileOffsetToData = 0; FileOffsetToRelocations = 0; RelocationCount = 0; - Index = -1; + Index = UninitializedIndex; + // Clear any csects we have stored. + for (auto *Group : Groups) + Group->Csects.clear(); } - Section(const char *N, XCOFF::SectionTypeFlags Flags, bool IsVirtual) + Section(const char *N, XCOFF::SectionTypeFlags Flags, bool IsVirtual, + CsectGroups Groups) : Address(0), Size(0), FileOffsetToData(0), FileOffsetToRelocations(0), - RelocationCount(0), Flags(Flags), Index(-1), IsVirtual(IsVirtual) { + RelocationCount(0), Flags(Flags), Index(UninitializedIndex), + IsVirtual(IsVirtual), Groups(Groups) { strncpy(Name, N, XCOFF::NameSize); } }; class XCOFFObjectWriter : public MCObjectWriter { - // Type to be used for a container representing a set of csects with - // (approximately) the same storage mapping class. For example all the csects - // with a storage mapping class of `xmc_pr` will get placed into the same - // container. - using CsectGroup = std::deque; + + uint32_t SymbolTableEntryCount = 0; + uint32_t SymbolTableOffset = 0; support::endian::Writer W; std::unique_ptr TargetObjectWriter; StringTableBuilder Strings; - // The non-empty sections, in the order they will appear in the section header - // table. - std::vector
Sections; + // CsectGroups. These store the csects which make up different parts of + // the sections. Should have one for each set of csects that get mapped into + // the same section and get handled in a 'similar' way. + CsectGroup ProgramCodeCsects{CsectGroup::LabelDefSupported}; + CsectGroup BSSCsects{CsectGroup::LabelDefUnsupported}; // The Predefined sections. Section Text; Section BSS; - // CsectGroups. These store the csects which make up different parts of - // the sections. Should have one for each set of csects that get mapped into - // the same section and get handled in a 'similar' way. - CsectGroup ProgramCodeCsects; - CsectGroup BSSCsects; + // All the XCOFF sections, in the order they will appear in the section header + // table. + std::array
Sections{&Text, &BSS}; - uint32_t SymbolTableEntryCount = 0; - uint32_t SymbolTableOffset = 0; + CsectGroup &getCsectGroup(const MCSectionXCOFF *MCSec); virtual void reset() override; @@ -190,18 +221,15 @@ XCOFFObjectWriter::XCOFFObjectWriter( std::unique_ptr MOTW, raw_pwrite_stream &OS) : W(OS, support::big), TargetObjectWriter(std::move(MOTW)), Strings(StringTableBuilder::XCOFF), - Text(".text", XCOFF::STYP_TEXT, /* IsVirtual */ false), - BSS(".bss", XCOFF::STYP_BSS, /* IsVirtual */ true) {} + Text(".text", XCOFF::STYP_TEXT, /* IsVirtual */ false, + CsectGroups{&ProgramCodeCsects}), + BSS(".bss", XCOFF::STYP_BSS, /* IsVirtual */ true, + CsectGroups{&BSSCsects}) {} void XCOFFObjectWriter::reset() { // Reset any sections we have written to, and empty the section header table. for (auto *Sec : Sections) Sec->reset(); - Sections.clear(); - - // Clear any csects we have stored. - ProgramCodeCsects.clear(); - BSSCsects.clear(); // Reset the symbol table and string table. SymbolTableEntryCount = 0; @@ -211,6 +239,27 @@ void XCOFFObjectWriter::reset() { MCObjectWriter::reset(); } +CsectGroup &XCOFFObjectWriter::getCsectGroup(const MCSectionXCOFF *MCSec) { + switch (MCSec->getMappingClass()) { + case XCOFF::XMC_PR: + assert(XCOFF::XTY_SD == MCSec->getCSectType() && + "Only an initialized csect can contain program code."); + return ProgramCodeCsects; + case XCOFF::XMC_RW: + if (XCOFF::XTY_CM == MCSec->getCSectType()) + return BSSCsects; + + report_fatal_error("Unhandled mapping of read-write csect to section."); + case XCOFF::XMC_BS: + assert(XCOFF::XTY_CM == MCSec->getCSectType() && + "Mapping invalid csect. CSECT with bss storage class must be " + "common type."); + return BSSCsects; + default: + report_fatal_error("Unhandled mapping of csect to section."); + } +} + void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { if (TargetObjectWriter->is64Bit()) @@ -231,33 +280,13 @@ void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, if (nameShouldBeInStringTable(MCSec->getSectionName())) Strings.add(MCSec->getSectionName()); - switch (MCSec->getMappingClass()) { - case XCOFF::XMC_PR: - assert(XCOFF::XTY_SD == MCSec->getCSectType() && - "Only an initialized csect can contain program code."); - ProgramCodeCsects.emplace_back(MCSec); - WrapperMap[MCSec] = &ProgramCodeCsects.back(); - break; - case XCOFF::XMC_RW: - if (XCOFF::XTY_CM == MCSec->getCSectType()) { - BSSCsects.emplace_back(MCSec); - WrapperMap[MCSec] = &BSSCsects.back(); - break; - } - report_fatal_error("Unhandled mapping of read-write csect to section."); - case XCOFF::XMC_TC0: - // TODO FIXME Handle emiting the TOC base. - break; - case XCOFF::XMC_BS: - assert(XCOFF::XTY_CM == MCSec->getCSectType() && - "Mapping invalid csect. CSECT with bss storage class must be " - "common type."); - BSSCsects.emplace_back(MCSec); - WrapperMap[MCSec] = &BSSCsects.back(); - break; - default: - report_fatal_error("Unhandled mapping of csect to section."); - } + // TODO FIXME Handle emiting the TOC base. + if (MCSec->getMappingClass() == XCOFF::XMC_TC0) + continue; + + CsectGroup &Group = getCsectGroup(MCSec); + Group.Csects.emplace_back(MCSec); + WrapperMap[MCSec] = &Group.Csects.back(); } for (const MCSymbol &S : Asm.symbols()) { @@ -292,21 +321,28 @@ void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &, void XCOFFObjectWriter::writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout) { - // Write the program code control sections one at a time. - uint32_t CurrentAddressLocation = Text.Address; - for (const auto &Csect : ProgramCodeCsects) { - if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation) - W.OS.write_zeros(PaddingSize); - Asm.writeSectionData(W.OS, Csect.MCCsect, Layout); - CurrentAddressLocation = Csect.Address + Csect.Size; - } + uint32_t CurrentAddressLocation = 0; + for (const auto *Section : Sections) { + // Nothing to write for this Section. + if (Section->Index == Section::UninitializedIndex || Section->IsVirtual) + continue; + + assert(CurrentAddressLocation == Section->Address && + "We should have no padding between sections."); + for (const auto *Group : Section->Groups) { + for (const auto &Csect : Group->Csects) { + if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation) + W.OS.write_zeros(PaddingSize); + Asm.writeSectionData(W.OS, Csect.MCCsect, Layout); + CurrentAddressLocation = Csect.Address + Csect.Size; + } + } - if (Text.Index != -1) { // The size of the tail padding in a section is the end virtual address of // the current section minus the the end virtual address of the last csect // in that section. if (uint32_t PaddingSize = - Text.Address + Text.Size - CurrentAddressLocation) + Section->Address + Section->Size - CurrentAddressLocation) W.OS.write_zeros(PaddingSize); } } @@ -472,25 +508,28 @@ void XCOFFObjectWriter::writeSectionHeaderTable() { } void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) { - // Print out symbol table for the program code. - for (const auto &Csect : ProgramCodeCsects) { - // Write out the control section first and then each symbol in it. - writeSymbolTableEntryForControlSection(Csect, Text.Index, - Csect.MCCsect->getStorageClass()); - for (const auto &Sym : Csect.Syms) - writeSymbolTableEntryForCsectMemberLabel( - Sym, Csect, Text.Index, Layout.getSymbolOffset(*Sym.MCSym)); - } + for (const auto *Section : Sections) { + for (const auto *Group : Section->Groups) { + if (Group->Csects.empty()) + continue; - // The BSS Section is special in that the csects must contain a single symbol, - // and the contained symbol cannot be represented in the symbol table as a - // label definition. - for (auto &Csect : BSSCsects) { - assert(Csect.Syms.size() == 1 && - "Uninitialized csect cannot contain more then 1 symbol."); - Symbol &Sym = Csect.Syms.back(); - writeSymbolTableEntryForControlSection(Csect, BSS.Index, - Sym.getStorageClass()); + const bool SupportLabelDef = Group->SupportLabelDef; + const int16_t SectionIndex = Section->Index; + for (const auto &Csect : Group->Csects) { + // Write out the control section first and then each symbol in it. + writeSymbolTableEntryForControlSection( + Csect, SectionIndex, Csect.MCCsect->getStorageClass()); + if (!SupportLabelDef) { + assert(Csect.Syms.size() == 1 && "Csect should only contain 1 symbol " + "which is its label definition."); + continue; + } + + for (const auto Sym : Csect.Syms) + writeSymbolTableEntryForCsectMemberLabel( + Sym, Csect, SectionIndex, Layout.getSymbolOffset(*(Sym.MCSym))); + } + } } } @@ -500,64 +539,59 @@ void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) { // section header table. uint32_t Address = 0; // Section indices are 1-based in XCOFF. - int16_t SectionIndex = 1; + int32_t SectionIndex = 1; // The first symbol table entry is for the file name. We are not emitting it // yet, so start at index 0. uint32_t SymbolTableIndex = 0; - // Text section comes first. - if (!ProgramCodeCsects.empty()) { - Sections.push_back(&Text); - Text.Index = SectionIndex++; - for (auto &Csect : ProgramCodeCsects) { - const MCSectionXCOFF *MCSec = Csect.MCCsect; - Csect.Address = alignTo(Address, MCSec->getAlignment()); - Csect.Size = Layout.getSectionAddressSize(MCSec); - Address = Csect.Address + Csect.Size; - Csect.SymbolTableIndex = SymbolTableIndex; - // 1 main and 1 auxiliary symbol table entry for the csect. - SymbolTableIndex += 2; - for (auto &Sym : Csect.Syms) { - Sym.SymbolTableIndex = SymbolTableIndex; - // 1 main and 1 auxiliary symbol table entry for each contained symbol + for (auto *Section : Sections) { + const bool IsEmpty = + llvm::all_of(Section->Groups, [](const CsectGroup *Group) { + return Group->Csects.empty(); + }); + if (IsEmpty) + continue; + + if (SectionIndex > MaxSectionIndex) + report_fatal_error("Section index overflow!"); + Section->Index = SectionIndex++; + + bool SectionAddressSet = false; + for (auto *Group : Section->Groups) { + if (Group->Csects.empty()) + continue; + + const bool SupportLabelDef = Group->SupportLabelDef; + for (auto &Csect : Group->Csects) { + const MCSectionXCOFF *MCSec = Csect.MCCsect; + Csect.Address = alignTo(Address, MCSec->getAlignment()); + Csect.Size = Layout.getSectionAddressSize(MCSec); + Address = Csect.Address + Csect.Size; + Csect.SymbolTableIndex = SymbolTableIndex; + // 1 main and 1 auxiliary symbol table entry for the csect. SymbolTableIndex += 2; + + if (!SupportLabelDef) + continue; + + for (auto &Sym : Csect.Syms) { + Sym.SymbolTableIndex = SymbolTableIndex; + // 1 main and 1 auxiliary symbol table entry for each contained + // symbol. + SymbolTableIndex += 2; + } + } + + if (!SectionAddressSet) { + Section->Address = Group->Csects.front().Address; + SectionAddressSet = true; } } + + // Make sure the address of the next section aligned to + // DefaultSectionAlign. Address = alignTo(Address, DefaultSectionAlign); - - // The first csect of a section can be aligned by adjusting the virtual - // address of its containing section instead of writing zeroes into the - // object file. - Text.Address = ProgramCodeCsects.front().Address; - - Text.Size = Address - Text.Address; - } - - // Data section Second. TODO - - // BSS Section third. - if (!BSSCsects.empty()) { - Sections.push_back(&BSS); - BSS.Index = SectionIndex++; - for (auto &Csect : BSSCsects) { - const MCSectionXCOFF *MCSec = Csect.MCCsect; - Csect.Address = alignTo(Address, MCSec->getAlignment()); - Csect.Size = Layout.getSectionAddressSize(MCSec); - Address = Csect.Address + Csect.Size; - Csect.SymbolTableIndex = SymbolTableIndex; - // 1 main and 1 auxiliary symbol table entry for the csect. - SymbolTableIndex += 2; - - assert(Csect.Syms.size() == 1 && - "csect in the BSS can only contain a single symbol."); - Csect.Syms[0].SymbolTableIndex = Csect.SymbolTableIndex; - } - // Pad out Address to the default alignment. This is to match how the system - // assembler handles the .bss section. Its size is always a multiple of 4. - Address = alignTo(Address, DefaultSectionAlign); - - BSS.Address = BSSCsects.front().Address; - BSS.Size = Address - BSS.Address; + Section->Size = Address - Section->Address; } SymbolTableEntryCount = SymbolTableIndex;