Index: llvm/lib/MC/XCOFFObjectWriter.cpp =================================================================== --- llvm/lib/MC/XCOFFObjectWriter.cpp +++ llvm/lib/MC/XCOFFObjectWriter.cpp @@ -73,6 +73,22 @@ : 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 LabelDefinitionUsage : bool { + UseLabelDefinition = true, + DoNotUseLabelDefinition = false + }; + + const LabelDefinitionUsage UseLabelDef; + 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 +110,62 @@ // Virtual sections do not need storage allocated in the object file. const bool IsVirtual; + // XCOFF have 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 to represent a section index that hasn't been + // initialized. + static constexpr int16_t UninitializedIndex = -3; + + 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::UseLabelDefinition}; + CsectGroup BSSCsects{CsectGroup::DoNotUseLabelDefinition}; // 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; + // The non-empty 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 +219,15 @@ 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 +237,29 @@ 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."); + } + + llvm_unreachable("Program code should not reach here."); +} + void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { if (TargetObjectWriter->is64Bit()) @@ -231,33 +280,13 @@ 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,26 @@ 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; - } + for (const auto *Section : Sections) { + // Nothing to write for this Section. + if (Section->Index == Section::UninitializedIndex || Section->IsVirtual) + continue; + + uint32_t CurrentAddressLocation = Section->Address; + 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 +506,28 @@ } 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)); - } - - // 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()); + for (const auto *Section : Sections) { + for (const auto *Group : Section->Groups) { + if (Group->Csects.empty()) + continue; + + const bool UseLabelDef = Group->UseLabelDef; + 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 (!UseLabelDef) { + 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 +537,51 @@ // 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 - SymbolTableIndex += 2; - } - } - Address = alignTo(Address, DefaultSectionAlign); + for (auto *Section : Sections) { + for (auto *Group : Section->Groups) { + if (Group->Csects.empty()) + continue; - // 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; + const bool UseLabelDef = Group->UseLabelDef; + for (auto &Csect : Group->Csects) { - Text.Size = Address - Text.Address; - } + 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; + Csect.Size = Layout.getSectionAddressSize(MCSec); + if (!UseLabelDef) + continue; + + for (auto &Sym : Csect.Syms) { + Sym.SymbolTableIndex = SymbolTableIndex; + // 1 main and 1 auxiliary symbol table entry for each contained + // symbol. + SymbolTableIndex += 2; + } + } - // 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; + if (Section->Index == Section::UninitializedIndex) { + assert(SectionIndex <= INT16_MAX && "Section index overflow!"); + Section->Index = SectionIndex++; + Section->Address = Group->Csects.front().Address; + } } - // 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; + // Make sure the address of the next section aligned to + // DefaultSectionAlign. + if (Section->Index != Section::UninitializedIndex) { + Address = alignTo(Address, DefaultSectionAlign); + Section->Size = Address - Section->Address; + } } SymbolTableEntryCount = SymbolTableIndex;