Index: llvm/include/llvm/MC/MCSectionXCOFF.h =================================================================== --- llvm/include/llvm/MC/MCSectionXCOFF.h +++ llvm/include/llvm/MC/MCSectionXCOFF.h @@ -57,6 +57,7 @@ StringRef getSectionName() const { return Name; } XCOFF::StorageMappingClass getMappingClass() const { return MappingClass; } + XCOFF::StorageClass getStorageClass() const { return StorageClass; } XCOFF::SymbolType getCSectType() const { return Type; } void PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, Index: llvm/lib/MC/MCXCOFFStreamer.cpp =================================================================== --- llvm/lib/MC/MCXCOFFStreamer.cpp +++ llvm/lib/MC/MCXCOFFStreamer.cpp @@ -27,9 +27,20 @@ : MCObjectStreamer(Context, std::move(MAB), std::move(OW), std::move(Emitter)) {} -bool MCXCOFFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, +bool MCXCOFFStreamer::EmitSymbolAttribute(MCSymbol *Sym, MCSymbolAttr Attribute) { - report_fatal_error("Symbol attributes not implemented for XCOFF."); + auto *Symbol = cast(Sym); + getAssembler().registerSymbol(*Symbol); + + switch (Attribute) { + case MCSA_Global: + Symbol->setStorageClass(XCOFF::C_EXT); + Symbol->setExternal(true); + break; + default: + report_fatal_error("Not implemented yet."); + } + return true; } void MCXCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, @@ -57,8 +68,18 @@ } void MCXCOFFStreamer::EmitInstToData(const MCInst &Inst, - const MCSubtargetInfo &) { - report_fatal_error("Instruction emission not implemented for XCOFF."); + const MCSubtargetInfo &STI) { + MCAssembler &Assembler = getAssembler(); + SmallVector Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + Assembler.getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI); + + // TODO: Handle Fixups later + + MCDataFragment *DF = getOrCreateDataFragment(&STI); + DF->setHasInstructions(STI); + DF->getContents().append(Code.begin(), Code.end()); } MCStreamer *llvm::createXCOFFStreamer(MCContext &Context, Index: llvm/lib/MC/XCOFFObjectWriter.cpp =================================================================== --- llvm/lib/MC/XCOFFObjectWriter.cpp +++ llvm/lib/MC/XCOFFObjectWriter.cpp @@ -57,10 +57,6 @@ 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) {} }; @@ -72,7 +68,7 @@ uint32_t Size; SmallVector Syms; - + StringRef getName() const { return MCCsect->getSectionName(); } ControlSection(const MCSectionXCOFF *MCSec) : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1) {} }; @@ -93,7 +89,7 @@ uint32_t RelocationCount; int32_t Flags; - uint16_t Index; + int16_t Index; // Virtual sections do not need storage allocated in the object file. const bool IsVirtual; @@ -151,9 +147,17 @@ uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override; + bool nameShouldBeInStringTable(const StringRef &); + void writeSymbolName(const StringRef &); + void writeSymbolTableEntryForCsectMemberLabel(const Symbol &, + const ControlSection &, int16_t, + uint64_t); + void writeSymbolTableEntryForControlSection(const ControlSection &, int16_t, + XCOFF::StorageClass); void writeFileHeader(); void writeSectionHeaderTable(); - void writeSymbolTable(); + void writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout); + void writeSymbolTable(const MCAsmLayout &Layout); // Called after all the csects and symbols have been processed by // `executePostLayoutBinding`, this function handles building up the majority @@ -163,7 +167,7 @@ // *) Assigns symbol table indices. // *) Builds up the section header table by adding any non-empty sections to // `Sections`. - void assignAddressesAndIndices(const llvm::MCAsmLayout &); + void assignAddressesAndIndices(const MCAsmLayout &); bool needsAuxiliaryHeader() const { /* TODO aux header support not implemented. */ @@ -207,8 +211,8 @@ MCObjectWriter::reset(); } -void XCOFFObjectWriter::executePostLayoutBinding( - llvm::MCAssembler &Asm, const llvm::MCAsmLayout &Layout) { +void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { if (TargetObjectWriter->is64Bit()) report_fatal_error("64-bit XCOFF object files are not supported yet."); @@ -222,11 +226,17 @@ assert(WrapperMap.find(MCSec) == WrapperMap.end() && "Cannot add a csect twice."); + // If the name does not fit in the storage provided in the symbol table + // entry, add it to the string table. + 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."); - // TODO FIXME Handle .text section csects. + ProgramCodeCsects.emplace_back(MCSec); + WrapperMap[MCSec] = &ProgramCodeCsects.back(); break; case XCOFF::XMC_RW: if (XCOFF::XTY_CM == MCSec->getCSectType()) { @@ -265,12 +275,10 @@ 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()); + // entry add it to the string table. + if (nameShouldBeInStringTable(XSym->getName())) + Strings.add(XSym->getName()); } - } Strings.finalize(); assignAddressesAndIndices(Layout); @@ -282,7 +290,15 @@ report_fatal_error("XCOFF relocations not supported."); } -uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &) { +void XCOFFObjectWriter::writeSections(const MCAssembler &Asm, + const MCAsmLayout &Layout) { + // Write the program code control sections one at a time. + for (const auto &Csect : ProgramCodeCsects) + Asm.writeSectionData(W.OS, Csect.MCCsect, Layout); +} + +uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { // We always emit a timestamp of 0 for reproducibility, so ensure incremental // linking is not enabled, in case, like with Windows COFF, such a timestamp // is incompatible with incremental linking of XCOFF. @@ -296,17 +312,106 @@ writeFileHeader(); writeSectionHeaderTable(); - // TODO writeSections(); + writeSections(Asm, Layout); // TODO writeRelocations(); - // TODO FIXME Finalize symbols. - writeSymbolTable(); + writeSymbolTable(Layout); // Write the string table. Strings.write(W.OS); return W.OS.tell() - StartOffset; } +bool XCOFFObjectWriter::nameShouldBeInStringTable(const StringRef &SymbolName) { + return SymbolName.size() > XCOFF::NameSize; +} + +void XCOFFObjectWriter::writeSymbolName(const StringRef &SymbolName) { + if (nameShouldBeInStringTable(SymbolName)) { + W.write(0); + W.write(Strings.getOffset(SymbolName)); + } else { + char Name[XCOFF::NameSize]; + std::strncpy(Name, SymbolName.data(), XCOFF::NameSize); + ArrayRef NameRef(Name, XCOFF::NameSize); + W.write(NameRef); + } +} + +void XCOFFObjectWriter::writeSymbolTableEntryForCsectMemberLabel( + const Symbol &SymbolRef, const ControlSection &CSectionRef, + int16_t SectionIndex, uint64_t SymbolOffset) { + // Name or Zeros and string table offset + writeSymbolName(SymbolRef.getName()); + + W.write(CSectionRef.Address + SymbolOffset); + W.write(SectionIndex); + // 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 symbol's visibilty is default? + // TODO Set the function indicator (bit 10, 0x0020) for functions + // when debugging is enabled. + W.write(0); + W.write(SymbolRef.getStorageClass()); + // Always 1 aux entry for now. + W.write(1); + + // Now output the auxiliary entry. + W.write(CSectionRef.SymbolTableIndex); + // Parameter typecheck hash. Not supported. + W.write(0); + // Typecheck section number. Not supported. + W.write(0); + // Symbol type: Label + W.write(XCOFF::XTY_LD); + // Storage mapping class. + W.write(CSectionRef.MCCsect->getMappingClass()); + // Reserved (x_stab). + W.write(0); + // Reserved (x_snstab). + W.write(0); +} + +void XCOFFObjectWriter::writeSymbolTableEntryForControlSection( + const ControlSection &CSectionRef, int16_t SectionIndex, + XCOFF::StorageClass StorageClass) { + // n_name, n_zeros, n_offset + writeSymbolName(CSectionRef.getName()); + // n_value + W.write(CSectionRef.Address); + // n_scnum + W.write(SectionIndex); + // 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 symbol's visibilty is default? + // TODO Set the function indicator (bit 10, 0x0020) for functions + // when debugging is enabled. + W.write(0); + // n_sclass + W.write(StorageClass); + // Always 1 aux entry for now. + W.write(1); + + // Now output the auxiliary entry. + W.write(CSectionRef.Size); + // Parameter typecheck hash. Not supported. + W.write(0); + // Typecheck section number. Not supported. + W.write(0); + // Symbol type. + W.write(getEncodedType(CSectionRef.MCCsect)); + // Storage mapping class. + W.write(CSectionRef.MCCsect->getMappingClass()); + // Reserved (x_stab). + W.write(0); + // Reserved (x_snstab). + W.write(0); +} + void XCOFFObjectWriter::writeFileHeader() { // Magic. W.write(0x01df); @@ -351,81 +456,75 @@ } } -void XCOFFObjectWriter::writeSymbolTable() { - assert(ProgramCodeCsects.size() == 0 && ".text csects not handled yet."); +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 &Sec : BSSCsects) { - assert(Sec.Syms.size() == 1 && + for (auto &Csect : BSSCsects) { + assert(Csect.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); + Symbol &Sym = Csect.Syms.back(); + writeSymbolTableEntryForControlSection(Csect, BSS.Index, + Sym.getStorageClass()); } } -void XCOFFObjectWriter::assignAddressesAndIndices( - const llvm::MCAsmLayout &Layout) { +void XCOFFObjectWriter::assignAddressesAndIndices(const 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; + uint32_t SectionStartAddress = 0; // Section indices are 1-based in XCOFF. - uint16_t SectionIndex = 1; + int16_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 + // Text section comes first. + if (!ProgramCodeCsects.empty()) { + Sections.push_back(&Text); + Text.Index = SectionIndex++; + Text.Address = SectionStartAddress; + uint32_t Address = SectionStartAddress; + for (auto &Csect : ProgramCodeCsects) { + 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); + 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); + Text.Size = Address - SectionStartAddress; + SectionStartAddress = Address; + } + // 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; + BSS.Address = SectionStartAddress; + uint32_t Address = SectionStartAddress; for (auto &Csect : BSSCsects) { const MCSectionXCOFF *MCSec = Csect.MCCsect; Address = alignTo(Address, MCSec->getAlignment()); @@ -443,7 +542,8 @@ // 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; + BSS.Size = Address - SectionStartAddress; + SectionStartAddress = Address; } SymbolTableEntryCount = SymbolTableIndex; Index: llvm/test/CodeGen/PowerPC/aix-return55.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/PowerPC/aix-return55.ll @@ -0,0 +1,11 @@ +; RUN: llc -mcpu=pwr9 -mtriple=powerpc-ibm-aix-xcoff -verify-machineinstrs < %s | FileCheck %s + + +define dso_local signext i32 @foo() { +entry: + ret i32 55 +; CHECK-LABEL: .foo +; CHECK: li 3, 55 +; CHECK: blr +} + Index: llvm/test/CodeGen/PowerPC/aix-xcoff-common.ll =================================================================== --- llvm/test/CodeGen/PowerPC/aix-xcoff-common.ll +++ llvm/test/CodeGen/PowerPC/aix-xcoff-common.ll @@ -39,16 +39,29 @@ ; OBJ-NEXT: AddressSize: 32bit ; OBJ-NEXT: FileHeader { ; OBJ-NEXT: Magic: 0x1DF -; OBJ-NEXT: NumberOfSections: 1 +; OBJ-NEXT: NumberOfSections: 2 ; OBJ-NEXT: TimeStamp: -; OBJ-NEXT: SymbolTableOffset: 0x3C -; OBJ-NEXT: SymbolTableEntries: 14 +; OBJ-NEXT: SymbolTableOffset: 0x64 +; OBJ-NEXT: SymbolTableEntries: 16 ; OBJ-NEXT: OptionalHeaderSize: 0x0 ; OBJ-NEXT: Flags: 0x0 ; OBJ-NEXT: } ; OBJ-NEXT: Sections [ ; OBJ-NEXT: Section { ; OBJ-NEXT: Index: 1 +; OBJ-NEXT: Name: .text +; OBJ-NEXT: PhysicalAddress: 0x0 +; OBJ-NEXT: VirtualAddress: 0x0 +; OBJ-NEXT: Size: 0x0 +; OBJ-NEXT: RawDataOffset: 0x64 +; OBJ-NEXT: RelocationPointer: 0x0 +; OBJ-NEXT: LineNumberPointer: 0x0 +; OBJ-NEXT: NumberOfRelocations: 0 +; OBJ-NEXT: NumberOfLineNumbers: 0 +; OBJ-NEXT: Type: STYP_TEXT (0x20) +; OBJ-NEXT: } +; OBJ-NEXT: Section { +; OBJ-NEXT: Index: 2 ; OBJ-NEXT: Name: .bss ; OBJ-NEXT: PhysicalAddress: 0x0 ; OBJ-NEXT: VirtualAddress: 0x0 @@ -68,8 +81,7 @@ ; SYMS-NEXT: AddressSize: 32bit ; SYMS-NEXT: Symbols [ ; SYMS-NEXT: Symbol { -; SYMS-NEXT: Index: [[#Index:]] -; SYMS-NEXT: Name: a +; SYMS: Index: [[#Index:]]{{[[:space:]].*}}Name: a ; SYMS-NEXT: Value (RelocatableAddress): 0x0 ; SYMS-NEXT: Section: .bss ; SYMS-NEXT: Type: 0x0 Index: llvm/test/CodeGen/PowerPC/aix-xcoff-lcomm.ll =================================================================== --- llvm/test/CodeGen/PowerPC/aix-xcoff-lcomm.ll +++ llvm/test/CodeGen/PowerPC/aix-xcoff-lcomm.ll @@ -24,16 +24,16 @@ ; OBJ-NEXT: AddressSize: 32bit ; OBJ-NEXT: FileHeader { ; OBJ-NEXT: Magic: 0x1DF -; OBJ-NEXT: NumberOfSections: 1 +; OBJ-NEXT: NumberOfSections: 2 ; OBJ-NEXT: TimeStamp: -; OBJ-NEXT: SymbolTableOffset: 0x3C -; OBJ-NEXT: SymbolTableEntries: 6 +; OBJ-NEXT: SymbolTableOffset: 0x64 +; OBJ-NEXT: SymbolTableEntries: 8 ; OBJ-NEXT: OptionalHeaderSize: 0x0 ; OBJ-NEXT: Flags: 0x0 ; OBJ-NEXT: } ; OBJ-NEXT: Sections [ -; OBJ-NEXT: Section { -; OBJ-NEXT: Index: 1 +; OBJ: Section { +; OBJ: Index: 2 ; OBJ-NEXT: Name: .bss ; OBJ-NEXT: PhysicalAddress: 0x0 ; OBJ-NEXT: VirtualAddress: 0x0 @@ -53,8 +53,7 @@ ; SYMS-NEXT: AddressSize: 32bit ; SYMS-NEXT: Symbols [ ; SYMS-NEXT: Symbol { -; SYMS-NEXT: Index: [[#Index:]] -; SYMS-NEXT: Name: a +; SYMS: Index: [[#Index:]]{{[[:space:]].*}}Name: a ; SYMS-NEXT: Value (RelocatableAddress): 0x0 ; SYMS-NEXT: Section: .bss ; SYMS-NEXT: Type: 0x0