Index: llvm/trunk/include/llvm/BinaryFormat/XCOFF.h =================================================================== --- llvm/trunk/include/llvm/BinaryFormat/XCOFF.h +++ llvm/trunk/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 NumberOfSections; + int32_t TimeStamp; + uint32_t SymbolTableFileOffset; + int32_t NumberOfSymbolTableEntries; + uint16_t AuxiliaryHeaderSize; + uint16_t Flags; +}; + +struct SectionHeader32 { + char Name[XCOFF::NameSize]; + uint32_t PhysicalAddress; + uint32_t VirtualAddress; + uint32_t Size; + uint32_t FileOffsetToData; + uint32_t FileOffsetToRelocations; + uint32_t FileOffsetToLineNumbers; + uint16_t NumberOfRelocations; + uint16_t NumberOfLineNumbers; + int32_t Flags; +}; + } // end namespace XCOFF } // end namespace llvm Index: llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ llvm/trunk/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 Index: llvm/trunk/include/llvm/MC/MCContext.h =================================================================== --- llvm/trunk/include/llvm/MC/MCContext.h +++ llvm/trunk/include/llvm/MC/MCContext.h @@ -508,7 +508,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. Index: llvm/trunk/include/llvm/MC/MCSectionXCOFF.h =================================================================== --- llvm/trunk/include/llvm/MC/MCSectionXCOFF.h +++ llvm/trunk/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."); } Index: llvm/trunk/include/llvm/MC/MCSymbolXCOFF.h =================================================================== --- llvm/trunk/include/llvm/MC/MCSymbolXCOFF.h +++ llvm/trunk/include/llvm/MC/MCSymbolXCOFF.h @@ -8,6 +8,7 @@ #ifndef LLVM_MC_MCSYMBOLXCOFF_H #define LLVM_MC_MCSYMBOLXCOFF_H +#include "llvm/ADT/Optional.h" #include "llvm/BinaryFormat/XCOFF.h" #include "llvm/MC/MCSymbol.h" @@ -19,6 +20,21 @@ : MCSymbol(SymbolKindXCOFF, Name, isTemporary) {} static bool classof(const MCSymbol *S) { return S->isXCOFF(); } + + void setStorageClass(XCOFF::StorageClass SC) { + assert((!StorageClass.hasValue() || StorageClass.getValue() == SC) && + "Redefining StorageClass of XCOFF MCSymbol."); + StorageClass = SC; + }; + + XCOFF::StorageClass getStorageClass() const { + assert(StorageClass.hasValue() && + "StorageClass not set on XCOFF MCSymbol."); + return StorageClass.getValue(); + } + +private: + Optional StorageClass; }; } // end namespace llvm Index: llvm/trunk/include/llvm/MC/StringTableBuilder.h =================================================================== --- llvm/trunk/include/llvm/MC/StringTableBuilder.h +++ llvm/trunk/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; Index: llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -1840,9 +1840,11 @@ if (Kind.isBSSLocal() || Kind.isCommon()) { SmallString<128> Name; getNameWithPrefix(Name, GO, TM); + XCOFF::StorageClass SC = + TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GO); return getContext().getXCOFFSection( Name, Kind.isBSSLocal() ? XCOFF::XMC_BS : XCOFF::XMC_RW, XCOFF::XTY_CM, - Kind, /* BeginSymbolName */ nullptr); + SC, Kind, /* BeginSymbolName */ nullptr); } if (Kind.isText()) @@ -1879,3 +1881,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."); + } +} Index: llvm/trunk/lib/MC/MCContext.cpp =================================================================== --- llvm/trunk/lib/MC/MCContext.cpp +++ llvm/trunk/lib/MC/MCContext.cpp @@ -538,6 +538,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. @@ -555,7 +556,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(); Index: llvm/trunk/lib/MC/MCObjectFileInfo.cpp =================================================================== --- llvm/trunk/lib/MC/MCObjectFileInfo.cpp +++ llvm/trunk/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, Index: llvm/trunk/lib/MC/MCXCOFFStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCXCOFFStreamer.cpp +++ llvm/trunk/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; @@ -32,7 +33,20 @@ void MCXCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { - report_fatal_error("Emiting common symbols not implemented for XCOFF."); + 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); + EmitZeros(Size); } void MCXCOFFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, Index: llvm/trunk/lib/MC/StringTableBuilder.cpp =================================================================== --- llvm/trunk/lib/MC/StringTableBuilder.cpp +++ llvm/trunk/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. Index: llvm/trunk/lib/MC/XCOFFObjectWriter.cpp =================================================================== --- llvm/trunk/lib/MC/XCOFFObjectWriter.cpp +++ llvm/trunk/lib/MC/XCOFFObjectWriter.cpp @@ -10,18 +10,139 @@ // //===----------------------------------------------------------------------===// +#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 and read-only data. +// .data --> contains initialized data, function descriptors, and the TOC. +// .bss --> contains uninitialized data. +// Each of these sections is composed of 'Control Sections'. A Control Section +// is more commonly referred to as a csect. A csect 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, with the exception of +// XMC_RW which gets mapped to either .data or .bss based on whether it's +// explicitly initialized or not. +// +// 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 = 4; + +// Packs the csect's alignment and type into a byte. +uint8_t getEncodedType(const MCSectionXCOFF *); + +// Wrapper around an MCSymbolXCOFF. +struct Symbol { + const MCSymbolXCOFF *const 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::NameSize; + } + + Symbol(const MCSymbolXCOFF *MCSym) : MCSym(MCSym), SymbolTableIndex(-1) {} +}; + +// Wrapper for an MCSectionXCOFF. +struct ControlSection { + const MCSectionXCOFF *const 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 separately, e.g. the .data section containing read-write, descriptor, +// TOCBase and TOC-entry csects. +struct Section { + char Name[XCOFF::NameSize]; + // 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; + int32_t Flags; + + uint16_t Index; + + // Virtual 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; + Index = -1; + } + + Section(const char *N, XCOFF::SectionTypeFlags Flags, bool IsVirtual) + : Address(0), Size(0), FileOffsetToData(0), FileOffsetToRelocations(0), + RelocationCount(0), Flags(Flags), Index(-1), IsVirtual(IsVirtual) { + 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 ControlSections = std::deque; + 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; + + // 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 +151,32 @@ 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 &); + + bool + needsAuxiliaryHeader() const { /* TODO aux header support not implemented. */ + return false; + } + + // Returns the size of the auxiliary header to be written to the object file. + size_t auxiliaryHeaderSize() const { + assert(!needsAuxiliaryHeader() && + "Auxiliary header support not implemented."); + return 0; + } + public: XCOFFObjectWriter(std::unique_ptr MOTW, raw_pwrite_stream &OS); @@ -37,11 +184,87 @@ 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)), + Strings(StringTableBuilder::XCOFF), + 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( + llvm::MCAssembler &Asm, const llvm::MCAsmLayout &Layout) { + if (TargetObjectWriter->is64Bit()) + report_fatal_error("64-bit XCOFF object files are not supported yet."); + + // Maps the MC Section representation to its corresponding ControlSection + // wrapper. Needed for finding the ControlSection to insert an MCSymbol into + // from its containing MCSectionXCOFF. + DenseMap WrapperMap; + + 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 initialized csect can contain program code."); + // TODO FIXME Handle .text section csects. + 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."); + 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); + + // 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); + + // If the name does not fit in the storage provided in the symbol table + // entry, add it to the string table. + const Symbol &WrapperSym = WrapperMap[ContainingCsect]->Syms.back(); + if (WrapperSym.nameInStringTable()) { + Strings.add(WrapperSym.getName()); + } + } -void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &, - const MCAsmLayout &) { - // TODO Implement once we have sections and symbols to handle. + Strings.finalize(); + assignAddressesAndIndices(Layout); } void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &, @@ -62,27 +285,193 @@ 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::NameSize); + 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 line-number 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."); + + // 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 &Sec : BSSCsects) { + assert(Sec.Syms.size() == 1 && + "Uninitialized csect cannot contain more then 1 symbol."); + Symbol &Sym = Sec.Syms.back(); + + // Write the symbol's name. + if (Sym.nameInStringTable()) { + W.write(0); + W.write(Strings.getOffset(Sym.getName())); + } else { + char Name[XCOFF::NameSize]; + std::strncpy(Name, Sym.getName().data(), XCOFF::NameSize); + ArrayRef NameRef(Name, XCOFF::NameSize); + 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 visibility 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. We place the shared address 0 immediately after the + // 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. We are not emitting it + // 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++; + assert(alignTo(Address, DefaultSectionAlign) == Address && + "Improperly aligned address for section."); + 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 && + "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.Size = Address - StartAddress; + } + + SymbolTableEntryCount = SymbolTableIndex; + + // Calculate the RawPointer value for each section. + uint64_t RawPointer = sizeof(XCOFF::FileHeader32) + auxiliaryHeaderSize() + + 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 to? + // 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() <= 0x07u) && "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 + // bitwise-or in the csect type. + uint8_t EncodedAlign = Log2Align << 3; + return EncodedAlign | Sec->getCSectType(); } } // end anonymous namespace Index: llvm/trunk/lib/Target/PowerPC/PPCAsmPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ llvm/trunk/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); Index: llvm/trunk/test/CodeGen/PowerPC/aix-xcoff-common.ll =================================================================== --- llvm/trunk/test/CodeGen/PowerPC/aix-xcoff-common.ll +++ llvm/trunk/test/CodeGen/PowerPC/aix-xcoff-common.ll @@ -1,5 +1,14 @@ ; 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 + +; RUN: not llc -mtriple powerpc64-ibm-aix-xcoff -filetype=obj -o %t.o 2>&1 \ +; RUN: < %s | FileCheck --check-prefix=XCOFF64 %s + +; XCOFF64: LLVM ERROR: 64-bit XCOFF object files are not supported yet. + @a = common global i32 0, align 4 @b = common global i64 0, align 8 @c = common global i16 0, align 2 @@ -9,7 +18,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 +28,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: ]