Skip to content

Commit

Permalink
[NFC][XCOFF][AIX] Serialize object file writing for each CsectGroup
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jasonliudev committed Oct 24, 2019
1 parent e5f485c commit 78207e1
Showing 1 changed file with 163 additions and 129 deletions.
292 changes: 163 additions & 129 deletions llvm/lib/MC/XCOFFObjectWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down Expand Up @@ -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
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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())
Expand All @@ -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()) {
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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));
}

// 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 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)));
}
}
}
}

Expand All @@ -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;
}
}
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;
if (!SupportLabelDef)
continue;

Text.Size = Address - Text.Address;
}
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 (!SectionAddressSet) {
Section->Address = Group->Csects.front().Address;
SectionAddressSet = true;
}
}
// 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.
Address = alignTo(Address, DefaultSectionAlign);
Section->Size = Address - Section->Address;
}

SymbolTableEntryCount = SymbolTableIndex;
Expand Down

0 comments on commit 78207e1

Please sign in to comment.