diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h --- a/llvm/include/llvm/BinaryFormat/XCOFF.h +++ b/llvm/include/llvm/BinaryFormat/XCOFF.h @@ -147,6 +147,29 @@ XTY_CM = 3 ///< Common csect definition. For uninitialized storage. }; +struct FileHeader32 { + uint16_t Magic; + uint16_t SectionCount; + int32_t TimeStamp; + uint32_t SymbolTableFileOffset; + int32_t SymbolTableEntryCount; + uint16_t AuxiliaryHeaderSize; + uint16_t Flags; +}; + +struct SectionHeader32 { + char Name[XCOFF::SectionNameSize]; + uint32_t PhysicalAddress; + uint32_t VirtualAddress; + uint32_t Size; + uint32_t FileOffsetToData; + uint32_t FileOffsetToRelocations; + uint32_t FileOffsetToLineNumbers; + uint16_t RelocationCount; + uint16_t LineNumberCount; + int32_t Flags; +}; + } // end namespace XCOFF } // end namespace llvm diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h --- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -14,6 +14,7 @@ #ifndef LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H #define LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCExpr.h" #include "llvm/Target/TargetLoweringObjectFile.h" @@ -230,6 +231,8 @@ MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const override; + + static XCOFF::StorageClass getStorageClassForGlobal(const GlobalObject *GO); }; } // end namespace llvm diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h --- a/llvm/include/llvm/MC/MCContext.h +++ b/llvm/include/llvm/MC/MCContext.h @@ -490,7 +490,9 @@ MCSectionXCOFF *getXCOFFSection(StringRef Section, XCOFF::StorageMappingClass MappingClass, - XCOFF::SymbolType CSectType, SectionKind K, + XCOFF::SymbolType CSectType, + XCOFF::StorageClass StorageClass, + SectionKind K, const char *BeginSymName = nullptr); // Create and save a copy of STI and return a reference to the copy. diff --git a/llvm/include/llvm/MC/MCSectionXCOFF.h b/llvm/include/llvm/MC/MCSectionXCOFF.h --- a/llvm/include/llvm/MC/MCSectionXCOFF.h +++ b/llvm/include/llvm/MC/MCSectionXCOFF.h @@ -37,11 +37,13 @@ StringRef Name; XCOFF::StorageMappingClass MappingClass; XCOFF::SymbolType Type; + XCOFF::StorageClass StorageClass; MCSectionXCOFF(StringRef Section, XCOFF::StorageMappingClass SMC, - XCOFF::SymbolType ST, SectionKind K, MCSymbol *Begin) + XCOFF::SymbolType ST, XCOFF::StorageClass SC, SectionKind K, + MCSymbol *Begin) : MCSection(SV_XCOFF, K, Begin), Name(Section), MappingClass(SMC), - Type(ST) { + Type(ST), StorageClass(SC) { assert((ST == XCOFF::XTY_SD || ST == XCOFF::XTY_CM) && "Invalid or unhandled type for csect."); } diff --git a/llvm/include/llvm/MC/MCSymbolXCOFF.h b/llvm/include/llvm/MC/MCSymbolXCOFF.h --- a/llvm/include/llvm/MC/MCSymbolXCOFF.h +++ b/llvm/include/llvm/MC/MCSymbolXCOFF.h @@ -19,6 +19,12 @@ : MCSymbol(SymbolKindXCOFF, Name, isTemporary) {} static bool classof(const MCSymbol *S) { return S->isXCOFF(); } + + void setStorageClass(XCOFF::StorageClass SC) { StorageClass = SC; }; + XCOFF::StorageClass getStorageClass() const { return StorageClass; } + +private: + XCOFF::StorageClass StorageClass; }; } // end namespace llvm diff --git a/llvm/include/llvm/MC/StringTableBuilder.h b/llvm/include/llvm/MC/StringTableBuilder.h --- a/llvm/include/llvm/MC/StringTableBuilder.h +++ b/llvm/include/llvm/MC/StringTableBuilder.h @@ -22,7 +22,7 @@ /// Utility for building string tables with deduplicated suffixes. class StringTableBuilder { public: - enum Kind { ELF, WinCOFF, MachO, RAW, DWARF }; + enum Kind { ELF, WinCOFF, MachO, RAW, DWARF, XCOFF}; private: DenseMap StringIndexMap; diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -1854,8 +1854,11 @@ if (Kind.isCommon()) { SmallString<128> Name; getNameWithPrefix(Name, GO, TM); - return getContext().getXCOFFSection(Name, XCOFF::XMC_RW, XCOFF::XTY_CM, - Kind, /* BeginSymbolName */ nullptr); + XCOFF::StorageClass SC = + TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GO); + return getContext().getXCOFFSection(Name, XCOFF::XMC_RW, XCOFF::XTY_CM, SC, + Kind, + /* BeginSymbolName */ nullptr); } if (Kind.isText()) @@ -1892,3 +1895,19 @@ const TargetMachine &TM) const { report_fatal_error("XCOFF not yet implemented."); } + +XCOFF::StorageClass TargetLoweringObjectFileXCOFF::getStorageClassForGlobal( + const GlobalObject *GO) { + switch (GO->getLinkage()) { + case GlobalValue::InternalLinkage: + return XCOFF::C_HIDEXT; + case GlobalValue::ExternalLinkage: + case GlobalValue::CommonLinkage: + return XCOFF::C_EXT; + case GlobalValue::ExternalWeakLinkage: + return XCOFF::C_WEAKEXT; + default: + report_fatal_error( + "Unhandled linkage when mapping linkage to StorageClass."); + } +} diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp --- a/llvm/lib/MC/MCContext.cpp +++ b/llvm/lib/MC/MCContext.cpp @@ -532,6 +532,7 @@ MCSectionXCOFF *MCContext::getXCOFFSection(StringRef Section, XCOFF::StorageMappingClass SMC, XCOFF::SymbolType Type, + XCOFF::StorageClass SC, SectionKind Kind, const char *BeginSymName) { // Do the lookup. If we have a hit, return it. @@ -549,7 +550,7 @@ Begin = createTempSymbol(BeginSymName, false); MCSectionXCOFF *Result = new (XCOFFAllocator.Allocate()) - MCSectionXCOFF(CachedName, SMC, Type, Kind, Begin); + MCSectionXCOFF(CachedName, SMC, Type, SC, Kind, Begin); Entry.second = Result; auto *F = new MCDataFragment(); diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp --- a/llvm/lib/MC/MCObjectFileInfo.cpp +++ b/llvm/lib/MC/MCObjectFileInfo.cpp @@ -767,9 +767,9 @@ // get placed into this csect. The choice of csect name is not a property of // the ABI or object file format. For example, the XL compiler uses an unnamed // csect for program code. - TextSection = - Ctx->getXCOFFSection(".text", XCOFF::StorageMappingClass::XMC_PR, - XCOFF::XTY_SD, SectionKind::getText()); + TextSection = Ctx->getXCOFFSection( + ".text", XCOFF::StorageMappingClass::XMC_PR, XCOFF::XTY_SD, + XCOFF::C_HIDEXT, SectionKind::getText()); } void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, bool PIC, diff --git a/llvm/lib/MC/MCXCOFFStreamer.cpp b/llvm/lib/MC/MCXCOFFStreamer.cpp --- a/llvm/lib/MC/MCXCOFFStreamer.cpp +++ b/llvm/lib/MC/MCXCOFFStreamer.cpp @@ -14,6 +14,7 @@ #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSymbolXCOFF.h" #include "llvm/Support/TargetRegistry.h" using namespace llvm; @@ -31,8 +32,21 @@ } void MCXCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment) { - report_fatal_error("Emiting common symbols not implemented for XCOFF."); + unsigned ByteAlignment) { + getAssembler().registerSymbol(*Symbol); + Symbol->setExternal((cast(Symbol))->getStorageClass() != + XCOFF::C_HIDEXT); + Symbol->setCommon(Size, ByteAlignment); + + // Need to add this symbol to the current Fragment which will belong to the + // containing CSECT. + auto *F = dyn_cast_or_null(getCurrentFragment()); + assert(F && "Expected a valid section with a fragment set."); + Symbol->setFragment(F); + + // Emit the alignment and storage for the variable to the section. + EmitValueToAlignment(ByteAlignment, 0, 1, 0); + EmitZeros(Size); } void MCXCOFFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, diff --git a/llvm/lib/MC/StringTableBuilder.cpp b/llvm/lib/MC/StringTableBuilder.cpp --- a/llvm/lib/MC/StringTableBuilder.cpp +++ b/llvm/lib/MC/StringTableBuilder.cpp @@ -38,6 +38,7 @@ // Start the table with a NUL byte. Size = 1; break; + case XCOFF: case WinCOFF: // Make room to write the table size later. Size = 4; @@ -67,9 +68,12 @@ if (!Data.empty()) memcpy(Buf + P.second, Data.data(), Data.size()); } - if (K != WinCOFF) - return; - support::endian::write32le(Buf, Size); + // The COFF formats store the size of the string table in the first 4 bytes. + // For Windows, the format is little-endian; for AIX it is big-endian. + if (K == WinCOFF) + support::endian::write32le(Buf, Size); + else if (K == XCOFF) + support::endian::write32be(Buf, Size); } // Returns the character at Pos from end of a string. diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp --- a/llvm/lib/MC/XCOFFObjectWriter.cpp +++ b/llvm/lib/MC/XCOFFObjectWriter.cpp @@ -10,18 +10,143 @@ // //===----------------------------------------------------------------------===// +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSectionXCOFF.h" +#include "llvm/MC/MCSymbolXCOFF.h" #include "llvm/MC/MCValue.h" #include "llvm/MC/MCXCOFFObjectWriter.h" +#include "llvm/MC/StringTableBuilder.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" + +#include using namespace llvm; +// An XCOFF object file has a limited set of predefined sections. The most +// important ones for us (right now) are: +// .text --> contains program code. +// .data --> contains intialized data, function descriptors and the TOC. +// .bss --> contains uninitialized data. +// Each of these sections is composed of 'Control Sections', more commonly +// referred to as csects. A control section is an indivisible unit of code or +// data, and acts as a container for symbols. A csect is mapped +// into a section based on its storage-mapping class. +// +// We don't represent the sections in the MC layer as there is nothing +// interesting about them at at that level: they carry information that is +// only relevant to the ObjectWriter, so we materialize them in this class. namespace { +constexpr unsigned DefaultSectionAlign = 16; + +// The system assembler will only emit Data and BSS sections that are a multiple +// of 4. +constexpr unsigned SectionSizeMultiple = 4; + +// Packs the csects alignment and type into a byte. +uint8_t getEncodedType(const MCSectionXCOFF *); + +// Wrapper around an MCSymbolXCOFF. +struct Symbol { + const MCSymbolXCOFF *MCSym; + uint32_t SymbolTableIndex; + + XCOFF::StorageClass getStorageClass() const { + return MCSym->getStorageClass(); + } + StringRef getName() const { return MCSym->getName(); } + bool nameInStringTable() const { + return MCSym->getName().size() > XCOFF::SymbolNameSize; + } + + Symbol(const MCSymbolXCOFF *MCSym) : MCSym(MCSym), SymbolTableIndex(-1) {} +}; + +// Wrapper for an MCSectionXCOFF. +struct ControlSection { + const MCSectionXCOFF *MCCSect; + uint32_t SymbolTableIndex; + uint32_t Address; + uint32_t Size; + + SmallVector Syms; + + ControlSection(const MCSectionXCOFF *MCSec) + : MCCSect(MCSec), SymbolTableIndex(-1), Address(-1) {} +}; + +// 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 +// stored seperatly eg: the .data section containing read-write, descriptor, +// TOCBase and TOC-entry csects. +struct Section { + char Name[XCOFF::SectionNameSize]; + // The physical/virtual address of the section. For an object file + // these values are equivalent. + uint32_t Address; + uint32_t Size; + uint32_t FileOffsetToData; + uint32_t FileOffsetToRelocations; + uint32_t RelocationCount; + uint32_t Flags; + + uint32_t Alignment; + uint16_t Index; + + // Virutal sections do not need storage allocated in the object file. + const bool IsVirtual; + + void reset() { + Address = 0; + Size = 0; + FileOffsetToData = 0; + FileOffsetToRelocations = 0; + RelocationCount = 0; + Alignment = DefaultSectionAlign; + Index = -1; + } + + Section(const char *N, XCOFF::SectionTypeFlags Flags, bool IsVirtual) + : Address(0), Size(0), FileOffsetToData(0), FileOffsetToRelocations(0), + RelocationCount(0), Flags(Flags), Alignment(DefaultSectionAlign), + Index(-1), IsVirtual(IsVirtual) { + strncpy(Name, N, XCOFF::SectionNameSize); + } +}; + class XCOFFObjectWriter : public MCObjectWriter { + // Container for a set of csects with (approximately) the same storage mapping + // class. For example all the csects with a storage mapping class of `xmc_pc` + // will get placed into the same container. + using ControlSections = std::deque; + support::endian::Writer W; std::unique_ptr TargetObjectWriter; + StringTableBuilder Strings{StringTableBuilder::XCOFF}; + + // The non-empty sections, in the order they will appear in the section header + // table. + std::vector
Sections; + + // The Predefined sections. + Section Text; + Section BSS; + + // ControlSections. 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. + ControlSections ProgramCodeCSects; + ControlSections BSSCSects; + + uint32_t SymbolTableEntryCount = 0; + uint32_t SymbolTableOffset = 0; + + virtual void reset() override; void executePostLayoutBinding(MCAssembler &, const MCAsmLayout &) override; @@ -30,6 +155,20 @@ uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override; + void writeFileHeader(); + void writeSectionHeaderTable(); + void writeSymbolTable(); + + // Called after all the csects and symbols have been processed by + // `executePostLayoutBinding`, this function handles building up the majority + // of the structures in the object file representation. Namely: + // *) Calculates physical/virtual addresses, raw_pointer offsets, and section + // sizes. + // *) Assigns symbol table indices. + // *) Builds up the section header table, by adding any non-empty sections to + // `Sections`. + void assignAddressesAndIndices(const llvm::MCAsmLayout &); + public: XCOFFObjectWriter(std::unique_ptr MOTW, raw_pwrite_stream &OS); @@ -37,11 +176,92 @@ XCOFFObjectWriter::XCOFFObjectWriter( std::unique_ptr MOTW, raw_pwrite_stream &OS) - : W(OS, support::big), TargetObjectWriter(std::move(MOTW)) {} + : W(OS, support::big), TargetObjectWriter(std::move(MOTW)), + Text(".text", XCOFF::STYP_TEXT, /* IsVirtual */ false), + BSS(".bss", XCOFF::STYP_BSS, /* IsVirtual */ true) {} + +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; + SymbolTableOffset = 0; + Strings.clear(); + + MCObjectWriter::reset(); +} -void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &, - const MCAsmLayout &) { - // TODO Implement once we have sections and symbols to handle. +void XCOFFObjectWriter::executePostLayoutBinding( + llvm::MCAssembler &Asm, const llvm::MCAsmLayout &Layout) { + // Maps the MC Section representation to its corrresponding ControlSection + // wrapper. Needed for finding the ControlSection to insert an MCSymbol into + // from its containing MCSectionXCOFF. + DenseMap WrapperMap; + + // Creates the csect wrapper in VecSec, adds to the map, and adjusts the + // alignment of the containing section accordingly. + auto Add = [&WrapperMap](Section *Sec, ControlSections &CSections, + const MCSectionXCOFF *CSect) { + unsigned Align = CSect->getAlignment(); + Sec->Alignment = std::max(Align, Sec->Alignment); + CSections.emplace_back(CSect); + WrapperMap[CSect] = &CSections.back(); + }; + + for (const auto &S : Asm) { + const MCSectionXCOFF *MCSec = dyn_cast(&S); + assert(WrapperMap.find(MCSec) == WrapperMap.end() && + "Cannot add a CSect twice."); + + switch (MCSec->getMappingClass()) { + case XCOFF::XMC_PR: { + assert(XCOFF::XTY_SD == MCSec->getCSectType() && + "Only an initilized csect can contain program code."); + Add(&Text, ProgramCodeCSects, MCSec); + break; + } + case XCOFF::XMC_RW: + if (XCOFF::XTY_CM == MCSec->getCSectType()) { + Add(&BSS, BSSCSects, MCSec); + break; + } + report_fatal_error("Unhandled mapping of read-write csect to section"); + default: + report_fatal_error("Unhandled mapping of csect to section"); + } + } + + for (const MCSymbol &S : Asm.symbols()) { + // Nothing to do for temporary symbols. + if (S.isTemporary()) + continue; + const MCSymbolXCOFF *XSym = cast(&S); + + // If the name does not fit in the storage provided in the symbol table + // entry add it to the string table. + if (XSym->getName().size() >= XCOFF::SymbolNameSize) { + Strings.add(XSym->getName()); + } + + // Map the symbol into its containing csect. + MCSectionXCOFF *ContainingCSect = + dyn_cast(XSym->getFragment(false)->getParent()); + assert(WrapperMap.find(ContainingCSect) != WrapperMap.end() && + "Expected containing csect to exist in map"); + + // Lookup the containing csect and add the symbol to it. + WrapperMap[ContainingCSect]->Syms.emplace_back(XSym); + } + + Strings.finalize(); + assignAddressesAndIndices(Layout); } void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &, @@ -62,27 +282,186 @@ uint64_t StartOffset = W.OS.tell(); - // TODO FIXME Assign section numbers/finalize sections. + writeFileHeader(); + writeSectionHeaderTable(); + // TODO writeSections(); + // TODO writeRelocations(); // TODO FIXME Finalize symbols. + writeSymbolTable(); + // Write the string table. + Strings.write(W.OS); + return W.OS.tell() - StartOffset; +} + +void XCOFFObjectWriter::writeFileHeader() { // Magic. W.write(0x01df); // Number of sections. - W.write(0); + W.write(Sections.size()); // Timestamp field. For reproducible output we write a 0, which represents no // timestamp. W.write(0); // Byte Offset to the start of the symbol table. - W.write(0); + W.write(SymbolTableOffset); // Number of entries in the symbol table. - W.write(0); + W.write(SymbolTableEntryCount); // Size of the optional header. W.write(0); // Flags. W.write(0); +} - return W.OS.tell() - StartOffset; +void XCOFFObjectWriter::writeSectionHeaderTable() { + for (const auto Sec : Sections) { + // Write Name. + ArrayRef NameRef(Sec->Name, XCOFF::SectionNameSize); + W.write(NameRef); + // Write the Physical Address and Virtual Address. In an object file these + // are the same. + W.write(Sec->Address); + W.write(Sec->Address); + W.write(Sec->Size); + W.write(Sec->FileOffsetToData); + // Relocation pointer and Lineno pointer. Not supported yet. + W.write(0); + W.write(0); + // Relocation and Linno counts. Not supported yet. + W.write(0); + W.write(0); + W.write(Sec->Flags); + } +} + +void XCOFFObjectWriter::writeSymbolTable() { + assert((ProgramCodeCSects.size() == 1 && + ProgramCodeCSects.back().Syms.size() == 0) && + ".text csects not handled yet."); + + // BSS Section is unique in that the csects contain a single symbol, and the + // contained symbol does not need a label definition. + for (auto &Sec : BSSCSects) { + assert(Sec.Syms.size() == 1 && + "Uninitialized csect cannot contain more then 1 symbol."); + Symbol &Sym = Sec.Syms.back(); + + // Write the symbols name. + if (Sym.nameInStringTable()) { + W.write(0); + W.write(Strings.getOffset(Sym.getName())); + } else { + char Name[XCOFF::SymbolNameSize]; + std::strncpy(Name, Sym.getName().data(), XCOFF::SymbolNameSize); + ArrayRef NameRef(Name, XCOFF::SymbolNameSize); + W.write(NameRef); + } + + W.write(Sec.Address); + W.write(BSS.Index); + // Basic/Derived type. See the description of the n_type field for symbol + // table entries for a detailed description. Since we don't yet support + // visibility, and all other bits are either optionally set or reserved, + // this is always zero. + // TODO FIXME How to assert a symbols visibilty is default? + W.write(0); + + W.write(Sym.getStorageClass()); + // Always 1 aux entry for now. + W.write(1); + + W.write(Sec.Size); + // Parameter typecheck hash. Not supported. + W.write(0); + // Typecheck section number. Not supported. + W.write(0); + // Symbol type. + W.write(getEncodedType(Sec.MCCSect)); + // Storage mapping class. + W.write(Sec.MCCSect->getMappingClass()); + // Reserved (x_stab). + W.write(0); + // Reserved (x_snstab). + W.write(0); + } +} + +void XCOFFObjectWriter::assignAddressesAndIndices( + const llvm::MCAsmLayout &Layout) { + // The address corrresponds to the address of sections and symbols in the + // object file. Address 0 is immediatly after the file header and section + // header table. + uint32_t Address = 0; + // Section indices are 1-based in XCOFF. + uint16_t SectionIndex = 1; + // The first symbol table entry is for the file name. Which we are not + // emitting yet, so start at index 0. + uint32_t SymbolTableIndex = 0; + + // Text section comes first. TODO + // Data section Second. TODO + + // BSS Section third. + if (!BSSCSects.empty()) { + Sections.push_back(&BSS); + BSS.Index = SectionIndex++; + Address = alignTo(Address, BSS.Alignment); + uint32_t StartAddress = Address; + for (auto &Csect : BSSCSects) { + const MCSectionXCOFF *MCSec = Csect.MCCSect; + Address = alignTo(Address, MCSec->getAlignment()); + Csect.Address = Address; + Address += Layout.getSectionAddressSize(MCSec); + Csect.SymbolTableIndex = SymbolTableIndex; + // 1 main and 1 auxiliary symbol table entry for the csect. + SymbolTableIndex += 2; + Csect.Size = Layout.getSectionAddressSize(MCSec); + + assert(Csect.Syms.size() == 1 && + +"Csects in the BSS can only contain a single symbol."); + Csect.Syms[0].SymbolTableIndex = Csect.SymbolTableIndex; + } + // There will be a csect definition for each symbol in the .bss section. + // Each of which has 2 symbol table entries. + SymbolTableEntryCount += BSSCSects.size() * 2; + + // Pad out Address to a 4 byte alignment. This is to match how the system + // assembler handles the .bss section. It's size is always a multiple of 4. + Address = alignTo(Address, SectionSizeMultiple); + BSS.Size = Address - StartAddress; + } + + // Calculate the RawPointer value for each section. + uint64_t RawPointer = sizeof(XCOFF::FileHeader32) + + Sections.size() * sizeof(XCOFF::SectionHeader32); + for (auto Sec : Sections) { + if (!Sec->IsVirtual) { + Sec->FileOffsetToData = RawPointer; + RawPointer += Sec->Size; + } + } + + // TODO Add in Relocation storage to the RawPointer Calculation. + // TODO What to align the SymbolTable too? + // TODO Error check that the number of symbol table entries fits in 32-bits + // signed ... + if (SymbolTableEntryCount) + SymbolTableOffset = RawPointer; +} + +// Takes the log base 2 of the alignment and shifts the result into the 5 most +// significant bits of a byte, then or's in the csect type into the least +// significant 3 bits. +uint8_t getEncodedType(const MCSectionXCOFF *Sec) { + unsigned Align = Sec->getAlignment(); + assert(isPowerOf2_32(Align) && "Alignment must be a power of 2."); + assert(((Sec->getCSectType() & 0xF8) == 0) && "Csect type exceeds 3-bits"); + unsigned Log2Align = Log2_32(Align); + // Result is a number in the range [0, 31] which fits in the 5 least + // significant bits. Shift this value into the 5 most significant bits, and + // or in the csect type. + uint8_t EncodedAlign = (Log2Align & 0xFF) << 3; + return EncodedAlign | Sec->getCSectType(); } } // end anonymous namespace diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -1667,8 +1667,10 @@ getObjFileLowering().SectionForGlobal(GV, GVKind, TM)); OutStreamer->SwitchSection(CSect); - // Create the symbol and emit it. + // Create the symbol, set its storage class and emit it. MCSymbolXCOFF *XSym = cast(getSymbol(GV)); + XSym->setStorageClass( + TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GV)); const DataLayout &DL = GV->getParent()->getDataLayout(); unsigned Align = GV->getAlignment() ? GV->getAlignment() : DL.getPreferredAlignment(GV); diff --git a/llvm/test/CodeGen/PowerPC/aix-xcoff-common.ll b/llvm/test/CodeGen/PowerPC/aix-xcoff-common.ll --- a/llvm/test/CodeGen/PowerPC/aix-xcoff-common.ll +++ b/llvm/test/CodeGen/PowerPC/aix-xcoff-common.ll @@ -1,5 +1,9 @@ ; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck %s +; RUN: llc -mtriple powerpc-ibm-aix-xcoff -filetype=obj -o %t.o < %s +; RUN: llvm-readobj --section-headers --file-header %t.o | \ +; RUN: FileCheck --check-prefix=OBJ %s + @a = common global i32 0, align 4 @b = common global i64 0, align 8 @c = common global i16 0, align 2 @@ -9,7 +13,7 @@ @over_aligned = common local_unnamed_addr global double 0.000000e+00, align 32 -@array = common local_unnamed_addr global [32 x i8] zeroinitializer, align 1 +@array = common local_unnamed_addr global [33 x i8] zeroinitializer, align 1 ; CHECK: .csect .text[PR] ; CHECK-NEXT: .file @@ -19,4 +23,33 @@ ; CHECK-NEXT: .comm d,8,3 ; CHECK-NEXT: .comm f,4,2 ; CHECK-NEXT: .comm over_aligned,8,5 -; CHECK-NEXT: .comm array,32,0 +; CHECK-NEXT: .comm array,33,0 + +; OBJ: File: {{.*}}aix-xcoff-common.ll.tmp.o +; OBJ-NEXT: Format: aixcoff-rs6000 +; OBJ-NEXT: Arch: powerpc +; OBJ-NEXT: AddressSize: 32bit +; OBJ-NEXT: FileHeader { +; OBJ-NEXT: Magic: 0x1DF +; OBJ-NEXT: NumberOfSections: 1 +; OBJ-NEXT: TimeStamp: +; OBJ-NEXT: SymbolTableOffset: 0x3C +; OBJ-NEXT: SymbolTableEntries: 14 +; OBJ-NEXT: OptionalHeaderSize: 0x0 +; OBJ-NEXT: Flags: 0x0 +; OBJ-NEXT: } +; OBJ-NEXT: Sections [ +; OBJ-NEXT: Section { +; OBJ-NEXT: Index: 1 +; OBJ-NEXT: Name: .bss +; OBJ-NEXT: PhysicalAddress: 0x0 +; OBJ-NEXT: VirtualAddress: 0x0 +; OBJ-NEXT: Size: 0x6C +; OBJ-NEXT: RawDataOffset: 0x0 +; OBJ-NEXT: RelocationPointer: 0x0 +; OBJ-NEXT: LineNumberPointer: 0x0 +; OBJ-NEXT: NumberOfRelocations: 0 +; OBJ-NEXT: NumberOfLineNumbers: 0 +; OBJ-NEXT: Type: STYP_BSS (0x80) +; OBJ-NEXT: } +; OBJ-NEXT: ]