forked from OSchip/llvm-project
[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
This commit is contained in:
parent
e5f485c3bd
commit
78207e1f23
|
@ -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<ControlSection> Csects;
|
||||
};
|
||||
|
||||
using CsectGroups = std::deque<CsectGroup *>;
|
||||
|
||||
// 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<ControlSection>;
|
||||
|
||||
uint32_t SymbolTableEntryCount = 0;
|
||||
uint32_t SymbolTableOffset = 0;
|
||||
|
||||
support::endian::Writer W;
|
||||
std::unique_ptr<MCXCOFFObjectTargetWriter> TargetObjectWriter;
|
||||
StringTableBuilder Strings;
|
||||
|
||||
// The non-empty sections, in the order they will appear in the section header
|
||||
// table.
|
||||
std::vector<Section *> 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<Section *const, 2> 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<MCXCOFFObjectTargetWriter> 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;
|
||||
|
|
Loading…
Reference in New Issue