diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:51:42 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:51:42 +0000 |
commit | 1d5ae1026e831016fc29fd927877c86af904481f (patch) | |
tree | 2cdfd12620fcfa5d9e4a0389f85368e8e36f63f9 /lib/MC | |
parent | e6d1592492a3a379186bfb02bd0f4eda0669c0d5 (diff) | |
download | src-1d5ae1026e831016fc29fd927877c86af904481f.tar.gz src-1d5ae1026e831016fc29fd927877c86af904481f.zip |
Vendor import of stripped llvm trunk r375505, the last commit before thevendor/llvm/llvm-trunk-r375505vendor/llvm
upstream Subversion repository was made read-only, and the LLVM project
migrated to GitHub:
https://llvm.org/svn/llvm-project/llvm/trunk@375505
Notes
Notes:
svn path=/vendor/llvm/dist/; revision=353940
svn path=/vendor/llvm/llvm-r375505/; revision=353941; tag=vendor/llvm/llvm-trunk-r375505
Diffstat (limited to 'lib/MC')
32 files changed, 1272 insertions, 430 deletions
diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index 2c68723a12f8..6f160e491cea 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -36,6 +36,7 @@ #include "llvm/MC/MCSymbolELF.h" #include "llvm/MC/MCValue.h" #include "llvm/MC/StringTableBuilder.h" +#include "llvm/Support/Alignment.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" @@ -336,7 +337,7 @@ public: } // end anonymous namespace void ELFWriter::align(unsigned Alignment) { - uint64_t Padding = OffsetToAlignment(W.OS.tell(), Alignment); + uint64_t Padding = offsetToAlignment(W.OS.tell(), Align(Alignment)); W.OS.write_zeros(Padding); } @@ -511,6 +512,19 @@ static uint8_t mergeTypeForSet(uint8_t origType, uint8_t newType) { return Type; } +static bool isIFunc(const MCSymbolELF *Symbol) { + while (Symbol->getType() != ELF::STT_GNU_IFUNC) { + const MCSymbolRefExpr *Value; + if (!Symbol->isVariable() || + !(Value = dyn_cast<MCSymbolRefExpr>(Symbol->getVariableValue())) || + Value->getKind() != MCSymbolRefExpr::VK_None || + mergeTypeForSet(Symbol->getType(), ELF::STT_GNU_IFUNC) != ELF::STT_GNU_IFUNC) + return false; + Symbol = &cast<MCSymbolELF>(Value->getSymbol()); + } + return true; +} + void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex, ELFSymbolData &MSD, const MCAsmLayout &Layout) { const auto &Symbol = cast<MCSymbolELF>(*MSD.Symbol); @@ -524,6 +538,8 @@ void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex, // Binding and Type share the same byte as upper and lower nibbles uint8_t Binding = Symbol.getBinding(); uint8_t Type = Symbol.getType(); + if (isIFunc(&Symbol)) + Type = ELF::STT_GNU_IFUNC; if (Base) { Type = mergeTypeForSet(Type, Base->getType()); } @@ -622,7 +638,7 @@ void ELFWriter::computeSymbolTable( unsigned EntrySize = is64Bit() ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; MCSectionELF *SymtabSection = Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, EntrySize, ""); - SymtabSection->setAlignment(is64Bit() ? 8 : 4); + SymtabSection->setAlignment(is64Bit() ? Align(8) : Align(4)); SymbolTableIndex = addToSectionTable(SymtabSection); align(SymtabSection->getAlignment()); @@ -720,7 +736,7 @@ void ELFWriter::computeSymbolTable( MCSectionELF *SymtabShndxSection = Ctx.getELFSection(".symtab_shndx", ELF::SHT_SYMTAB_SHNDX, 0, 4, ""); SymtabShndxSectionIndex = addToSectionTable(SymtabShndxSection); - SymtabShndxSection->setAlignment(4); + SymtabShndxSection->setAlignment(Align(4)); } ArrayRef<std::string> FileNames = Asm.getFileNames(); @@ -808,7 +824,7 @@ MCSectionELF *ELFWriter::createRelocationSection(MCContext &Ctx, MCSectionELF *RelaSection = Ctx.createELFRelSection( RelaSectionName, hasRelocationAddend() ? ELF::SHT_RELA : ELF::SHT_REL, Flags, EntrySize, Sec.getGroup(), &Sec); - RelaSection->setAlignment(is64Bit() ? 8 : 4); + RelaSection->setAlignment(is64Bit() ? Align(8) : Align(4)); return RelaSection; } @@ -895,7 +911,7 @@ void ELFWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec, Section.setFlags(Section.getFlags() | ELF::SHF_COMPRESSED); // Alignment field should reflect the requirements of // the compressed section header. - Section.setAlignment(is64Bit() ? 8 : 4); + Section.setAlignment(is64Bit() ? Align(8) : Align(4)); } else { // Add "z" prefix to section name. This is zlib-gnu style. MC.renameELFSection(&Section, (".z" + SectionName.drop_front(1)).str()); @@ -1119,7 +1135,7 @@ uint64_t ELFWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { if (!GroupIdx) { MCSectionELF *Group = Ctx.createELFGroupSection(SignatureSymbol); GroupIdx = addToSectionTable(Group); - Group->setAlignment(4); + Group->setAlignment(Align(4)); Groups.push_back(Group); } std::vector<const MCSectionELF *> &Members = @@ -1437,22 +1453,7 @@ void ELFObjectWriter::recordRelocation(MCAssembler &Asm, MCContext &Ctx = Asm.getContext(); if (const MCSymbolRefExpr *RefB = Target.getSymB()) { - // Let A, B and C being the components of Target and R be the location of - // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). - // If it is pcrel, we want to compute (A - B + C - R). - - // In general, ELF has no relocations for -B. It can only represent (A + C) - // or (A + C - R). If B = R + K and the relocation is not pcrel, we can - // replace B to implement it: (A - R - K + C) - if (IsPCRel) { - Ctx.reportError( - Fixup.getLoc(), - "No relocation available to represent this relative expression"); - return; - } - const auto &SymB = cast<MCSymbolELF>(RefB->getSymbol()); - if (SymB.isUndefined()) { Ctx.reportError(Fixup.getLoc(), Twine("symbol '") + SymB.getName() + @@ -1468,10 +1469,9 @@ void ELFObjectWriter::recordRelocation(MCAssembler &Asm, return; } - uint64_t SymBOffset = Layout.getSymbolOffset(SymB); - uint64_t K = SymBOffset - FixupOffset; + assert(!IsPCRel && "should have been folded"); IsPCRel = true; - C -= K; + C += FixupOffset - Layout.getSymbolOffset(SymB); } // We either rejected the fixup or folded B into C at this point. @@ -1489,38 +1489,35 @@ void ELFObjectWriter::recordRelocation(MCAssembler &Asm, } } - unsigned Type = TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel); - uint64_t OriginalC = C; - bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type); - if (!RelocateWithSymbol && SymA && !SymA->isUndefined()) - C += Layout.getSymbolOffset(*SymA); - - uint64_t Addend = 0; - if (hasRelocationAddend()) { - Addend = C; - C = 0; - } - - FixedValue = C; - const MCSectionELF *SecA = (SymA && SymA->isInSection()) ? cast<MCSectionELF>(&SymA->getSection()) : nullptr; if (!checkRelocation(Ctx, Fixup.getLoc(), &FixupSection, SecA)) return; + unsigned Type = TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel); + bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type); + uint64_t Addend = 0; + + FixedValue = !RelocateWithSymbol && SymA && !SymA->isUndefined() + ? C + Layout.getSymbolOffset(*SymA) + : C; + if (hasRelocationAddend()) { + Addend = FixedValue; + FixedValue = 0; + } + if (!RelocateWithSymbol) { const auto *SectionSymbol = SecA ? cast<MCSymbolELF>(SecA->getBeginSymbol()) : nullptr; if (SectionSymbol) SectionSymbol->setUsedInReloc(); - ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend, SymA, - OriginalC); + ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend, SymA, C); Relocations[&FixupSection].push_back(Rec); return; } - const auto *RenamedSymA = SymA; + const MCSymbolELF *RenamedSymA = SymA; if (SymA) { if (const MCSymbolELF *R = Renames.lookup(SymA)) RenamedSymA = R; @@ -1530,8 +1527,7 @@ void ELFObjectWriter::recordRelocation(MCAssembler &Asm, else RenamedSymA->setUsedInReloc(); } - ELFRelocationEntry Rec(FixupOffset, RenamedSymA, Type, Addend, SymA, - OriginalC); + ELFRelocationEntry Rec(FixupOffset, RenamedSymA, Type, Addend, SymA, C); Relocations[&FixupSection].push_back(Rec); } @@ -1551,7 +1547,7 @@ bool ELFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl( std::unique_ptr<MCObjectWriter> llvm::createELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW, raw_pwrite_stream &OS, bool IsLittleEndian) { - return llvm::make_unique<ELFSingleObjectWriter>(std::move(MOTW), OS, + return std::make_unique<ELFSingleObjectWriter>(std::move(MOTW), OS, IsLittleEndian); } @@ -1559,6 +1555,6 @@ std::unique_ptr<MCObjectWriter> llvm::createELFDwoObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW, raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS, bool IsLittleEndian) { - return llvm::make_unique<ELFDwoObjectWriter>(std::move(MOTW), OS, DwoOS, + return std::make_unique<ELFDwoObjectWriter>(std::move(MOTW), OS, DwoOS, IsLittleEndian); } diff --git a/lib/MC/MCAsmBackend.cpp b/lib/MC/MCAsmBackend.cpp index 9b1102cbe7d1..b800e9caee22 100644 --- a/lib/MC/MCAsmBackend.cpp +++ b/lib/MC/MCAsmBackend.cpp @@ -73,6 +73,7 @@ const MCFixupKindInfo &MCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { {"FK_Data_2", 0, 16, 0}, {"FK_Data_4", 0, 32, 0}, {"FK_Data_8", 0, 64, 0}, + {"FK_Data_6b", 0, 6, 0}, {"FK_PCRel_1", 0, 8, MCFixupKindInfo::FKF_IsPCRel}, {"FK_PCRel_2", 0, 16, MCFixupKindInfo::FKF_IsPCRel}, {"FK_PCRel_4", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, @@ -93,10 +94,12 @@ const MCFixupKindInfo &MCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { {"FK_Data_Add_2", 0, 16, 0}, {"FK_Data_Add_4", 0, 32, 0}, {"FK_Data_Add_8", 0, 64, 0}, + {"FK_Data_Add_6b", 0, 6, 0}, {"FK_Data_Sub_1", 0, 8, 0}, {"FK_Data_Sub_2", 0, 16, 0}, {"FK_Data_Sub_4", 0, 32, 0}, - {"FK_Data_Sub_8", 0, 64, 0}}; + {"FK_Data_Sub_8", 0, 64, 0}, + {"FK_Data_Sub_6b", 0, 6, 0}}; assert((size_t)Kind <= array_lengthof(Builtins) && "Unknown fixup kind"); return Builtins[Kind]; diff --git a/lib/MC/MCAsmInfoXCOFF.cpp b/lib/MC/MCAsmInfoXCOFF.cpp index 74c21f0c9e6d..65fe8848e20f 100644 --- a/lib/MC/MCAsmInfoXCOFF.cpp +++ b/lib/MC/MCAsmInfoXCOFF.cpp @@ -15,4 +15,21 @@ void MCAsmInfoXCOFF::anchor() {} MCAsmInfoXCOFF::MCAsmInfoXCOFF() { IsLittleEndian = false; HasDotTypeDotSizeDirective = false; + COMMDirectiveAlignmentIsInBytes = false; + LCOMMDirectiveAlignmentType = LCOMM::Log2Alignment; + UseDotAlignForAlignment = true; + AsciiDirective = nullptr; // not supported + AscizDirective = nullptr; // not supported + NeedsFunctionDescriptors = true; + HasDotLGloblDirective = true; + Data64bitsDirective = "\t.llong\t"; + SupportsQuotedNames = false; +} + +bool MCAsmInfoXCOFF::isValidUnquotedName(StringRef Name) const { + // FIXME: Remove this function when we stop using "TOC[TC0]" as a symbol name. + if (Name.equals("TOC[TC0]")) + return true; + + return MCAsmInfo::isValidUnquotedName(Name); } diff --git a/lib/MC/MCAsmMacro.cpp b/lib/MC/MCAsmMacro.cpp index ba4fb7d4f387..186a68b02a29 100644 --- a/lib/MC/MCAsmMacro.cpp +++ b/lib/MC/MCAsmMacro.cpp @@ -11,6 +11,7 @@ using namespace llvm; +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) void MCAsmMacroParameter::dump(raw_ostream &OS) const { OS << "\"" << Name << "\""; if (Required) @@ -39,3 +40,4 @@ void MCAsmMacro::dump(raw_ostream &OS) const { } OS << " (BEGIN BODY)" << Body << "(END BODY)\n"; } +#endif diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 7a2b0b8a1220..2d9c2cb21255 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAssembler.h" @@ -23,6 +24,7 @@ #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCRegister.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" @@ -66,7 +68,7 @@ public: std::unique_ptr<MCAsmBackend> asmbackend, bool showInst) : MCStreamer(Context), OSOwner(std::move(os)), OS(*OSOwner), MAI(Context.getAsmInfo()), InstPrinter(printer), - Assembler(llvm::make_unique<MCAssembler>( + Assembler(std::make_unique<MCAssembler>( Context, std::move(asmbackend), std::move(emitter), (asmbackend) ? asmbackend->createObjectWriter(NullStream) : nullptr)), @@ -162,6 +164,8 @@ public: void EmitCOFFSectionIndex(MCSymbol const *Symbol) override; void EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override; void EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override; + void EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlign) override; void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; @@ -254,9 +258,26 @@ public: unsigned SourceLineNum, const MCSymbol *FnStartSym, const MCSymbol *FnEndSym) override; + + void PrintCVDefRangePrefix( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges); + + void EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + codeview::DefRangeRegisterRelHeader DRHdr) override; + + void EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + codeview::DefRangeSubfieldRegisterHeader DRHdr) override; + + void EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + codeview::DefRangeRegisterHeader DRHdr) override; + void EmitCVDefRangeDirective( ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, - StringRef FixedSizePortion) override; + codeview::DefRangeFramePointerRelHeader DRHdr) override; + void EmitCVStringTableDirective() override; void EmitCVFileChecksumsDirective() override; void EmitCVFileChecksumOffsetDirective(unsigned FileNo) override; @@ -291,13 +312,13 @@ public: void EmitWinCFIFuncletOrFuncEnd(SMLoc Loc) override; void EmitWinCFIStartChained(SMLoc Loc) override; void EmitWinCFIEndChained(SMLoc Loc) override; - void EmitWinCFIPushReg(unsigned Register, SMLoc Loc) override; - void EmitWinCFISetFrame(unsigned Register, unsigned Offset, + void EmitWinCFIPushReg(MCRegister Register, SMLoc Loc) override; + void EmitWinCFISetFrame(MCRegister Register, unsigned Offset, SMLoc Loc) override; void EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) override; - void EmitWinCFISaveReg(unsigned Register, unsigned Offset, + void EmitWinCFISaveReg(MCRegister Register, unsigned Offset, SMLoc Loc) override; - void EmitWinCFISaveXMM(unsigned Register, unsigned Offset, + void EmitWinCFISaveXMM(MCRegister Register, unsigned Offset, SMLoc Loc) override; void EmitWinCFIPushFrame(bool Code, SMLoc Loc) override; void EmitWinCFIEndProlog(SMLoc Loc) override; @@ -630,6 +651,7 @@ bool MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_Global: // .globl/.global OS << MAI->getGlobalDirective(); break; + case MCSA_LGlobal: OS << "\t.lglobl\t"; break; case MCSA_Hidden: OS << "\t.hidden\t"; break; case MCSA_IndirectSymbol: OS << "\t.indirect_symbol\t"; break; case MCSA_Internal: OS << "\t.internal\t"; break; @@ -740,6 +762,24 @@ void MCAsmStreamer::EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) { EmitEOL(); } +// We need an XCOFF-specific version of this directive as the AIX syntax +// requires a QualName argument identifying the csect name and storage mapping +// class to appear before the alignment if we are specifying it. +void MCAsmStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + assert(MAI->getLCOMMDirectiveAlignmentType() == LCOMM::Log2Alignment && + "We only support writing log base-2 alignment format with XCOFF."); + assert(isPowerOf2_32(ByteAlignment) && "Alignment must be a power of 2."); + + OS << "\t.lcomm\t"; + Symbol->print(OS, MAI); + OS << ',' << Size; + OS << ',' << Symbol->getName(); + OS << ',' << Log2_32(ByteAlignment); + + EmitEOL(); +} + void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { assert(MAI->hasDotTypeDotSizeDirective()); OS << "\t.size\t"; @@ -1082,6 +1122,16 @@ void MCAsmStreamer::emitFill(const MCExpr &NumValues, int64_t Size, void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { + if (MAI->useDotAlignForAlignment()) { + if (!isPowerOf2_32(ByteAlignment)) + report_fatal_error("Only power-of-two alignments are supported " + "with .align."); + OS << "\t.align\t"; + OS << Log2_32(ByteAlignment); + EmitEOL(); + return; + } + // Some assemblers don't support non-power of two alignments, so we always // emit alignments as a power of two if possible. if (isPowerOf2_32(ByteAlignment)) { @@ -1376,9 +1426,8 @@ void MCAsmStreamer::EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId, PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym); } -void MCAsmStreamer::EmitCVDefRangeDirective( - ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, - StringRef FixedSizePortion) { +void MCAsmStreamer::PrintCVDefRangePrefix( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges) { OS << "\t.cv_def_range\t"; for (std::pair<const MCSymbol *, const MCSymbol *> Range : Ranges) { OS << ' '; @@ -1386,10 +1435,43 @@ void MCAsmStreamer::EmitCVDefRangeDirective( OS << ' '; Range.second->print(OS, MAI); } - OS << ", "; - PrintQuotedString(FixedSizePortion, OS); +} + +void MCAsmStreamer::EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + codeview::DefRangeRegisterRelHeader DRHdr) { + PrintCVDefRangePrefix(Ranges); + OS << ", reg_rel, "; + OS << DRHdr.Register << ", " << DRHdr.Flags << ", " + << DRHdr.BasePointerOffset; + EmitEOL(); +} + +void MCAsmStreamer::EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + codeview::DefRangeSubfieldRegisterHeader DRHdr) { + PrintCVDefRangePrefix(Ranges); + OS << ", subfield_reg, "; + OS << DRHdr.Register << ", " << DRHdr.OffsetInParent; + EmitEOL(); +} + +void MCAsmStreamer::EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + codeview::DefRangeRegisterHeader DRHdr) { + PrintCVDefRangePrefix(Ranges); + OS << ", reg, "; + OS << DRHdr.Register; + EmitEOL(); +} + +void MCAsmStreamer::EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + codeview::DefRangeFramePointerRelHeader DRHdr) { + PrintCVDefRangePrefix(Ranges); + OS << ", frame_ptr_rel, "; + OS << DRHdr.Offset; EmitEOL(); - this->MCStreamer::EmitCVDefRangeDirective(Ranges, FixedSizePortion); } void MCAsmStreamer::EmitCVStringTableDirective() { @@ -1453,9 +1535,8 @@ void MCAsmStreamer::EmitRegisterName(int64_t Register) { // just ones that map to LLVM register numbers and have known names. // Fall back to using the original number directly if no name is known. const MCRegisterInfo *MRI = getContext().getRegisterInfo(); - int LLVMRegister = MRI->getLLVMRegNumFromEH(Register); - if (LLVMRegister != -1) { - InstPrinter->printRegName(OS, LLVMRegister); + if (Optional<unsigned> LLVMRegister = MRI->getLLVMRegNum(Register, true)) { + InstPrinter->printRegName(OS, *LLVMRegister); return; } } @@ -1668,6 +1749,12 @@ void MCAsmStreamer::EmitWinEHHandlerData(SMLoc Loc) { // We only do this so the section switch that terminates the handler // data block is visible. WinEH::FrameInfo *CurFrame = getCurrentWinFrameInfo(); + + // Do nothing if no frame is open. MCStreamer should've already reported an + // error. + if (!CurFrame) + return; + MCSection *TextSec = &CurFrame->Function->getSection(); MCSection *XData = getAssociatedXDataSection(TextSec); SwitchSectionNoChange(XData); @@ -1676,18 +1763,21 @@ void MCAsmStreamer::EmitWinEHHandlerData(SMLoc Loc) { EmitEOL(); } -void MCAsmStreamer::EmitWinCFIPushReg(unsigned Register, SMLoc Loc) { +void MCAsmStreamer::EmitWinCFIPushReg(MCRegister Register, SMLoc Loc) { MCStreamer::EmitWinCFIPushReg(Register, Loc); - OS << "\t.seh_pushreg " << Register; + OS << "\t.seh_pushreg "; + InstPrinter->printRegName(OS, Register); EmitEOL(); } -void MCAsmStreamer::EmitWinCFISetFrame(unsigned Register, unsigned Offset, +void MCAsmStreamer::EmitWinCFISetFrame(MCRegister Register, unsigned Offset, SMLoc Loc) { MCStreamer::EmitWinCFISetFrame(Register, Offset, Loc); - OS << "\t.seh_setframe " << Register << ", " << Offset; + OS << "\t.seh_setframe "; + InstPrinter->printRegName(OS, Register); + OS << ", " << Offset; EmitEOL(); } @@ -1698,19 +1788,23 @@ void MCAsmStreamer::EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) { EmitEOL(); } -void MCAsmStreamer::EmitWinCFISaveReg(unsigned Register, unsigned Offset, +void MCAsmStreamer::EmitWinCFISaveReg(MCRegister Register, unsigned Offset, SMLoc Loc) { MCStreamer::EmitWinCFISaveReg(Register, Offset, Loc); - OS << "\t.seh_savereg " << Register << ", " << Offset; + OS << "\t.seh_savereg "; + InstPrinter->printRegName(OS, Register); + OS << ", " << Offset; EmitEOL(); } -void MCAsmStreamer::EmitWinCFISaveXMM(unsigned Register, unsigned Offset, +void MCAsmStreamer::EmitWinCFISaveXMM(MCRegister Register, unsigned Offset, SMLoc Loc) { MCStreamer::EmitWinCFISaveXMM(Register, Offset, Loc); - OS << "\t.seh_savexmm " << Register << ", " << Offset; + OS << "\t.seh_savexmm "; + InstPrinter->printRegName(OS, Register); + OS << ", " << Offset; EmitEOL(); } diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index c4f4d4c2870e..cf42fe85b8e5 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -30,6 +30,7 @@ #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCValue.h" +#include "llvm/Support/Alignment.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -321,7 +322,7 @@ uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, case MCFragment::FT_Align: { const MCAlignFragment &AF = cast<MCAlignFragment>(F); unsigned Offset = Layout.getFragmentOffset(&AF); - unsigned Size = OffsetToAlignment(Offset, AF.getAlignment()); + unsigned Size = offsetToAlignment(Offset, Align(AF.getAlignment())); // Insert extra Nops for code alignment if the target define // shouldInsertExtraNopBytesForCodeAlign target hook. @@ -840,6 +841,10 @@ void MCAssembler::layout(MCAsmLayout &Layout) { getBackend().shouldInsertFixupForCodeAlign(*this, Layout, *AF); } continue; + } else if (auto *FragWithFixups = + dyn_cast<MCDwarfCallFrameFragment>(&Frag)) { + Fixups = FragWithFixups->getFixups(); + Contents = FragWithFixups->getContents(); } else llvm_unreachable("Unknown fragment with fixups!"); for (const MCFixup &Fixup : Fixups) { @@ -969,13 +974,9 @@ bool MCAssembler::relaxDwarfLineAddr(MCAsmLayout &Layout, MCContext &Context = Layout.getAssembler().getContext(); uint64_t OldSize = DF.getContents().size(); int64_t AddrDelta; - bool Abs; - if (getBackend().requiresDiffExpressionRelocations()) - Abs = DF.getAddrDelta().evaluateAsAbsolute(AddrDelta, Layout); - else { - Abs = DF.getAddrDelta().evaluateKnownAbsolute(AddrDelta, Layout); - assert(Abs && "We created a line delta with an invalid expression"); - } + bool Abs = DF.getAddrDelta().evaluateKnownAbsolute(AddrDelta, Layout); + assert(Abs && "We created a line delta with an invalid expression"); + (void)Abs; int64_t LineDelta; LineDelta = DF.getLineDelta(); SmallVectorImpl<char> &Data = DF.getContents(); @@ -983,7 +984,7 @@ bool MCAssembler::relaxDwarfLineAddr(MCAsmLayout &Layout, raw_svector_ostream OSE(Data); DF.getFixups().clear(); - if (Abs) { + if (!getBackend().requiresDiffExpressionRelocations()) { MCDwarfLineAddr::Encode(Context, getDWARFLinetableParams(), LineDelta, AddrDelta, OSE); } else { @@ -1017,10 +1018,25 @@ bool MCAssembler::relaxDwarfCallFrameFragment(MCAsmLayout &Layout, bool Abs = DF.getAddrDelta().evaluateKnownAbsolute(AddrDelta, Layout); assert(Abs && "We created call frame with an invalid expression"); (void) Abs; - SmallString<8> &Data = DF.getContents(); + SmallVectorImpl<char> &Data = DF.getContents(); Data.clear(); raw_svector_ostream OSE(Data); - MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE); + DF.getFixups().clear(); + + if (getBackend().requiresDiffExpressionRelocations()) { + uint32_t Offset; + uint32_t Size; + MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE, &Offset, + &Size); + if (Size) { + DF.getFixups().push_back(MCFixup::create( + Offset, &DF.getAddrDelta(), + MCFixup::getKindForSizeInBits(Size /*In bits.*/, false /*isPCRel*/))); + } + } else { + MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE); + } + return OldSize != Data.size(); } diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index 0dc2e2d37caf..a69ee19e1a1a 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -58,11 +58,12 @@ AsSecureLogFileName("as-secure-log-file-name", MCContext::MCContext(const MCAsmInfo *mai, const MCRegisterInfo *mri, const MCObjectFileInfo *mofi, const SourceMgr *mgr, - bool DoAutoReset) + MCTargetOptions const *TargetOpts, bool DoAutoReset) : SrcMgr(mgr), InlineSrcMgr(nullptr), MAI(mai), MRI(mri), MOFI(mofi), Symbols(Allocator), UsedNames(Allocator), + InlineAsmUsedLabelNames(Allocator), CurrentDwarfLoc(0, 0, 0, DWARF2_FLAG_IS_STMT, 0, 0), - AutoReset(DoAutoReset) { + AutoReset(DoAutoReset), TargetOptions(TargetOpts) { SecureLogFile = AsSecureLogFileName; if (SrcMgr && SrcMgr->getNumBuffers()) @@ -90,6 +91,7 @@ void MCContext::reset() { XCOFFAllocator.DestroyAll(); MCSubtargetAllocator.DestroyAll(); + InlineAsmUsedLabelNames.clear(); UsedNames.clear(); Symbols.clear(); Allocator.Reset(); @@ -272,6 +274,10 @@ void MCContext::setSymbolValue(MCStreamer &Streamer, Streamer.EmitAssignment(Symbol, MCConstantExpr::create(Val, *this)); } +void MCContext::registerInlineAsmLabel(MCSymbol *Sym) { + InlineAsmUsedLabelNames[Sym->getName()] = Sym; +} + //===----------------------------------------------------------------------===// // Section Management //===----------------------------------------------------------------------===// @@ -531,6 +537,8 @@ MCSectionWasm *MCContext::getWasmSection(const Twine &Section, SectionKind Kind, 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. @@ -548,7 +556,7 @@ MCSectionXCOFF *MCContext::getXCOFFSection(StringRef Section, Begin = createTempSymbol(BeginSymName, false); MCSectionXCOFF *Result = new (XCOFFAllocator.Allocate()) - MCSectionXCOFF(CachedName, SMC, Kind, Begin); + MCSectionXCOFF(CachedName, SMC, Type, SC, Kind, Begin); Entry.second = Result; auto *F = new MCDataFragment(); @@ -690,6 +698,21 @@ void MCContext::reportError(SMLoc Loc, const Twine &Msg) { report_fatal_error(Msg, false); } +void MCContext::reportWarning(SMLoc Loc, const Twine &Msg) { + if (TargetOptions && TargetOptions->MCNoWarn) + return; + if (TargetOptions && TargetOptions->MCFatalWarnings) + reportError(Loc, Msg); + else { + // If we have a source manager use it. Otherwise, try using the inline + // source manager. + if (SrcMgr) + SrcMgr->PrintMessage(Loc, SourceMgr::DK_Warning, Msg); + else if (InlineSrcMgr) + InlineSrcMgr->PrintMessage(Loc, SourceMgr::DK_Warning, Msg); + } +} + void MCContext::reportFatalError(SMLoc Loc, const Twine &Msg) { reportError(Loc, Msg); diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index aae6fdf90931..bcc7c45afc01 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -544,8 +544,8 @@ Expected<unsigned> MCDwarfLineTable::tryGetFile(StringRef &Directory, FileNumber); } -bool isRootFile(const MCDwarfFile &RootFile, StringRef &Directory, - StringRef &FileName, Optional<MD5::MD5Result> Checksum) { +static bool isRootFile(const MCDwarfFile &RootFile, StringRef &Directory, + StringRef &FileName, Optional<MD5::MD5Result> Checksum) { if (RootFile.Name.empty() || RootFile.Name != FileName.data()) return false; return RootFile.Checksum == Checksum; @@ -1897,26 +1897,54 @@ void MCDwarfFrameEmitter::EmitAdvanceLoc(MCObjectStreamer &Streamer, } void MCDwarfFrameEmitter::EncodeAdvanceLoc(MCContext &Context, - uint64_t AddrDelta, - raw_ostream &OS) { + uint64_t AddrDelta, raw_ostream &OS, + uint32_t *Offset, uint32_t *Size) { // Scale the address delta by the minimum instruction length. AddrDelta = ScaleAddrDelta(Context, AddrDelta); + bool WithFixups = false; + if (Offset && Size) + WithFixups = true; + support::endianness E = Context.getAsmInfo()->isLittleEndian() ? support::little : support::big; if (AddrDelta == 0) { + if (WithFixups) { + *Offset = 0; + *Size = 0; + } } else if (isUIntN(6, AddrDelta)) { uint8_t Opcode = dwarf::DW_CFA_advance_loc | AddrDelta; - OS << Opcode; + if (WithFixups) { + *Offset = OS.tell(); + *Size = 6; + OS << uint8_t(dwarf::DW_CFA_advance_loc); + } else + OS << Opcode; } else if (isUInt<8>(AddrDelta)) { OS << uint8_t(dwarf::DW_CFA_advance_loc1); - OS << uint8_t(AddrDelta); + if (WithFixups) { + *Offset = OS.tell(); + *Size = 8; + OS.write_zeros(1); + } else + OS << uint8_t(AddrDelta); } else if (isUInt<16>(AddrDelta)) { OS << uint8_t(dwarf::DW_CFA_advance_loc2); - support::endian::write<uint16_t>(OS, AddrDelta, E); + if (WithFixups) { + *Offset = OS.tell(); + *Size = 16; + OS.write_zeros(2); + } else + support::endian::write<uint16_t>(OS, AddrDelta, E); } else { assert(isUInt<32>(AddrDelta)); OS << uint8_t(dwarf::DW_CFA_advance_loc4); - support::endian::write<uint32_t>(OS, AddrDelta, E); + if (WithFixups) { + *Offset = OS.tell(); + *Size = 32; + OS.write_zeros(4); + } else + support::endian::write<uint32_t>(OS, AddrDelta, E); } } diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 245dd063004f..fa2133078bfe 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -139,7 +139,7 @@ static void setSectionAlignmentForBundling(const MCAssembler &Assembler, MCSection *Section) { if (Section && Assembler.isBundlingEnabled() && Section->hasInstructions() && Section->getAlignment() < Assembler.getBundleAlignSize()) - Section->setAlignment(Assembler.getBundleAlignSize()); + Section->setAlignment(Align(Assembler.getBundleAlignSize())); } void MCELFStreamer::ChangeSection(MCSection *Section, @@ -277,6 +277,9 @@ bool MCELFStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { case MCSA_AltEntry: llvm_unreachable("ELF doesn't support the .alt_entry attribute"); + + case MCSA_LGlobal: + llvm_unreachable("ELF doesn't support the .lglobl attribute"); } return true; @@ -306,7 +309,7 @@ void MCELFStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size, // Update the maximum alignment of the section if necessary. if (ByteAlignment > Section.getAlignment()) - Section.setAlignment(ByteAlignment); + Section.setAlignment(Align(ByteAlignment)); SwitchSection(P.first, P.second); } else { diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp index ab53ed42778e..813c00f6f3bb 100644 --- a/lib/MC/MCExpr.cpp +++ b/lib/MC/MCExpr.cpp @@ -259,6 +259,8 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { case VK_PPC_TOC_LO: return "toc@l"; case VK_PPC_TOC_HI: return "toc@h"; case VK_PPC_TOC_HA: return "toc@ha"; + case VK_PPC_U: return "u"; + case VK_PPC_L: return "l"; case VK_PPC_DTPMOD: return "dtpmod"; case VK_PPC_TPREL_LO: return "tprel@l"; case VK_PPC_TPREL_HI: return "tprel@h"; @@ -373,6 +375,8 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) { .Case("toc@l", VK_PPC_TOC_LO) .Case("toc@h", VK_PPC_TOC_HI) .Case("toc@ha", VK_PPC_TOC_HA) + .Case("u", VK_PPC_U) + .Case("l", VK_PPC_L) .Case("tls", VK_PPC_TLS) .Case("dtpmod", VK_PPC_DTPMOD) .Case("tprel@l", VK_PPC_TPREL_LO) @@ -453,26 +457,28 @@ void MCTargetExpr::anchor() {} /* *** */ bool MCExpr::evaluateAsAbsolute(int64_t &Res) const { - return evaluateAsAbsolute(Res, nullptr, nullptr, nullptr); + return evaluateAsAbsolute(Res, nullptr, nullptr, nullptr, false); } bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAsmLayout &Layout) const { - return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr); + return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr, false); } bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAsmLayout &Layout, const SectionAddrMap &Addrs) const { - return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, &Addrs); + // Setting InSet causes us to absolutize differences across sections and that + // is what the MachO writer uses Addrs for. + return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, &Addrs, true); } bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const { - return evaluateAsAbsolute(Res, &Asm, nullptr, nullptr); + return evaluateAsAbsolute(Res, &Asm, nullptr, nullptr, false); } bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const { - return evaluateAsAbsolute(Res, Asm, nullptr, nullptr); + return evaluateAsAbsolute(Res, Asm, nullptr, nullptr, false); } bool MCExpr::evaluateKnownAbsolute(int64_t &Res, @@ -483,15 +489,6 @@ bool MCExpr::evaluateKnownAbsolute(int64_t &Res, bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, const MCAsmLayout *Layout, - const SectionAddrMap *Addrs) const { - // FIXME: The use if InSet = Addrs is a hack. Setting InSet causes us - // absolutize differences across sections and that is what the MachO writer - // uses Addrs for. - return evaluateAsAbsolute(Res, Asm, Layout, Addrs, Addrs); -} - -bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, - const MCAsmLayout *Layout, const SectionAddrMap *Addrs, bool InSet) const { MCValue Value; @@ -577,6 +574,24 @@ static void AttemptToFoldSymbolOffsetDifference( A = B = nullptr; } +static bool canFold(const MCAssembler *Asm, const MCSymbolRefExpr *A, + const MCSymbolRefExpr *B, bool InSet) { + if (InSet) + return true; + + if (!Asm->getBackend().requiresDiffExpressionRelocations()) + return true; + + const MCSymbol &CheckSym = A ? A->getSymbol() : B->getSymbol(); + if (!CheckSym.isInSection()) + return true; + + if (!CheckSym.getSection().hasInstructions()) + return true; + + return false; +} + /// Evaluate the result of an add between (conceptually) two MCValues. /// /// This routine conceptually attempts to construct an MCValue: @@ -617,8 +632,7 @@ EvaluateSymbolicAdd(const MCAssembler *Asm, const MCAsmLayout *Layout, // the backend requires this to be emitted as individual relocations, unless // the InSet flag is set to get the current difference anyway (used for // example to calculate symbol sizes). - if (Asm && - (InSet || !Asm->getBackend().requiresDiffExpressionRelocations())) { + if (Asm && canFold(Asm, LHS_A, LHS_B, InSet)) { // First, fold out any differences which are fully resolved. By // reassociating terms in // Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). diff --git a/lib/MC/MCInstPrinter.cpp b/lib/MC/MCInstPrinter.cpp index 159f4070fe9f..c5c06f323e68 100644 --- a/lib/MC/MCInstPrinter.cpp +++ b/lib/MC/MCInstPrinter.cpp @@ -64,12 +64,6 @@ StringRef MCInstPrinter::markup(StringRef s) const { else return ""; } -StringRef MCInstPrinter::markup(StringRef a, StringRef b) const { - if (getUseMarkup()) - return a; - else - return b; -} // For asm-style hex (e.g. 0ffh) the first digit always has to be a number. static bool needsLeadingZero(uint64_t Value) @@ -89,24 +83,25 @@ format_object<int64_t> MCInstPrinter::formatDec(int64_t Value) const { } format_object<int64_t> MCInstPrinter::formatHex(int64_t Value) const { - switch(PrintHexStyle) { + switch (PrintHexStyle) { case HexStyle::C: - if (Value < 0) + if (Value < 0) { + if (Value == std::numeric_limits<int64_t>::min()) + return format<int64_t>("-0x8000000000000000", Value); return format("-0x%" PRIx64, -Value); - else - return format("0x%" PRIx64, Value); + } + return format("0x%" PRIx64, Value); case HexStyle::Asm: if (Value < 0) { - if (needsLeadingZero((uint64_t)(-Value))) + if (Value == std::numeric_limits<int64_t>::min()) + return format<int64_t>("-8000000000000000h", Value); + if (needsLeadingZero(-(uint64_t)(Value))) return format("-0%" PRIx64 "h", -Value); - else - return format("-%" PRIx64 "h", -Value); - } else { - if (needsLeadingZero((uint64_t)(Value))) - return format("0%" PRIx64 "h", Value); - else - return format("%" PRIx64 "h", Value); + return format("-%" PRIx64 "h", -Value); } + if (needsLeadingZero((uint64_t)(Value))) + return format("0%" PRIx64 "h", Value); + return format("%" PRIx64 "h", Value); } llvm_unreachable("unsupported print style"); } diff --git a/lib/MC/MCInstrAnalysis.cpp b/lib/MC/MCInstrAnalysis.cpp index eca87f940bf5..54741fdd686d 100644 --- a/lib/MC/MCInstrAnalysis.cpp +++ b/lib/MC/MCInstrAnalysis.cpp @@ -33,3 +33,9 @@ bool MCInstrAnalysis::evaluateBranch(const MCInst &Inst, uint64_t Addr, Target = Addr+Size+Imm; return true; } + +Optional<uint64_t> +MCInstrAnalysis::evaluateMemoryOperandAddress(const MCInst &Inst, uint64_t Addr, + uint64_t Size) const { + return None; +} diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 613f255a4ea4..8e558a36b7a1 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -330,6 +330,7 @@ bool MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Sym, case MCSA_Protected: case MCSA_Weak: case MCSA_Local: + case MCSA_LGlobal: return false; case MCSA_Global: diff --git a/lib/MC/MCObjectFileInfo.cpp b/lib/MC/MCObjectFileInfo.cpp index 9f555abe1404..70c0409ece7a 100644 --- a/lib/MC/MCObjectFileInfo.cpp +++ b/lib/MC/MCObjectFileInfo.cpp @@ -28,7 +28,7 @@ static bool useCompactUnwind(const Triple &T) { return false; // aarch64 always has it. - if (T.getArch() == Triple::aarch64) + if (T.getArch() == Triple::aarch64 || T.getArch() == Triple::aarch64_32) return true; // armv7k always has it. @@ -57,7 +57,8 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { MachO::S_ATTR_STRIP_STATIC_SYMS | MachO::S_ATTR_LIVE_SUPPORT, SectionKind::getReadOnly()); - if (T.isOSDarwin() && T.getArch() == Triple::aarch64) + if (T.isOSDarwin() && + (T.getArch() == Triple::aarch64 || T.getArch() == Triple::aarch64_32)) SupportsCompactUnwindWithoutEHFrame = true; if (T.isWatchABI()) @@ -193,7 +194,7 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { if (T.getArch() == Triple::x86_64 || T.getArch() == Triple::x86) CompactUnwindDwarfEHFrameOnly = 0x04000000; // UNWIND_X86_64_MODE_DWARF - else if (T.getArch() == Triple::aarch64) + else if (T.getArch() == Triple::aarch64 || T.getArch() == Triple::aarch64_32) CompactUnwindDwarfEHFrameOnly = 0x03000000; // UNWIND_ARM64_MODE_DWARF else if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb) CompactUnwindDwarfEHFrameOnly = 0x04000000; // UNWIND_ARM_MODE_DWARF @@ -768,7 +769,12 @@ void MCObjectFileInfo::initXCOFFMCObjectFileInfo(const Triple &T) { // 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, SectionKind::getText()); + ".text", XCOFF::StorageMappingClass::XMC_PR, XCOFF::XTY_SD, + XCOFF::C_HIDEXT, SectionKind::getText()); + + DataSection = Ctx->getXCOFFSection( + ".data", XCOFF::StorageMappingClass::XMC_RW, XCOFF::XTY_SD, + XCOFF::C_HIDEXT, SectionKind::getData()); } void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, bool PIC, diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index 1587d8498666..83f6ab8fe332 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -27,7 +27,7 @@ MCObjectStreamer::MCObjectStreamer(MCContext &Context, std::unique_ptr<MCObjectWriter> OW, std::unique_ptr<MCCodeEmitter> Emitter) : MCStreamer(Context), - Assembler(llvm::make_unique<MCAssembler>( + Assembler(std::make_unique<MCAssembler>( Context, std::move(TAB), std::move(Emitter), std::move(OW))), EmitEHFrame(true), EmitDebugFrame(false) {} @@ -539,7 +539,7 @@ void MCObjectStreamer::EmitValueToAlignment(unsigned ByteAlignment, // Update the maximum alignment on the current section if necessary. MCSection *CurSec = getCurrentSectionOnly(); if (ByteAlignment > CurSec->getAlignment()) - CurSec->setAlignment(ByteAlignment); + CurSec->setAlignment(Align(ByteAlignment)); } void MCObjectStreamer::EmitCodeAlignment(unsigned ByteAlignment, diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 084f6a7a2e14..b59ac08ad6cc 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -22,6 +22,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" @@ -524,6 +525,19 @@ private: /// directives parsed by this class. StringMap<DirectiveKind> DirectiveKindMap; + // Codeview def_range type parsing. + enum CVDefRangeType { + CVDR_DEFRANGE = 0, // Placeholder + CVDR_DEFRANGE_REGISTER, + CVDR_DEFRANGE_FRAMEPOINTER_REL, + CVDR_DEFRANGE_SUBFIELD_REGISTER, + CVDR_DEFRANGE_REGISTER_REL + }; + + /// Maps Codeview def_range types --> CVDefRangeType enum, for + /// Codeview def_range types parsed by this class. + StringMap<CVDefRangeType> CVDefRangeTypeMap; + // ".ascii", ".asciz", ".string" bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated); bool parseDirectiveReloc(SMLoc DirectiveLoc); // ".reloc" @@ -671,6 +685,7 @@ private: bool parseDirectiveAddrsigSym(); void initializeDirectiveKindMap(); + void initializeCVDefRangeTypeMap(); }; } // end anonymous namespace @@ -714,12 +729,14 @@ AsmParser::AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, PlatformParser.reset(createWasmAsmParser()); break; case MCObjectFileInfo::IsXCOFF: - // TODO: Need to implement createXCOFFAsmParser for XCOFF format. + report_fatal_error( + "Need to implement createXCOFFAsmParser for XCOFF format."); break; } PlatformParser->Initialize(*this); initializeDirectiveKindMap(); + initializeCVDefRangeTypeMap(); NumOfMacroInstantiations = 0; } @@ -1142,7 +1159,9 @@ bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { } } - MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName); + MCSymbol *Sym = getContext().getInlineAsmLabel(SymbolName); + if (!Sym) + Sym = getContext().getOrCreateSymbol(SymbolName); // If this is an absolute variable reference, substitute it now to preserve // semantics in the face of reassignment. @@ -1737,6 +1756,7 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, StringMap<DirectiveKind>::const_iterator DirKindIt = DirectiveKindMap.find(IDVal); DirectiveKind DirKind = (DirKindIt == DirectiveKindMap.end()) + ? DK_NO_DIRECTIVE : DirKindIt->getValue(); switch (DirKind) { @@ -2895,11 +2915,27 @@ bool AsmParser::parseEscapedString(std::string &Data) { } // Recognize escaped characters. Note that this escape semantics currently - // loosely follows Darwin 'as'. Notably, it doesn't support hex escapes. + // loosely follows Darwin 'as'. ++i; if (i == e) return TokError("unexpected backslash at end of string"); + // Recognize hex sequences similarly to GNU 'as'. + if (Str[i] == 'x' || Str[i] == 'X') { + size_t length = Str.size(); + if (i + 1 >= length || !isHexDigit(Str[i + 1])) + return TokError("invalid hexadecimal escape sequence"); + + // Consume hex characters. GNU 'as' reads all hexadecimal characters and + // then truncates to the lower 16 bits. Seems reasonable. + unsigned Value = 0; + while (i + 1 < length && isHexDigit(Str[i + 1])) + Value = Value * 16 + hexDigitValue(Str[++i]); + + Data += (unsigned char)(Value & 0xFF); + continue; + } + // Recognize octal sequences. if ((unsigned)(Str[i] - '0') <= 7) { // Consume up to three octal characters. @@ -3825,6 +3861,13 @@ bool AsmParser::parseDirectiveCVInlineLinetable() { return false; } +void AsmParser::initializeCVDefRangeTypeMap() { + CVDefRangeTypeMap["reg"] = CVDR_DEFRANGE_REGISTER; + CVDefRangeTypeMap["frame_ptr_rel"] = CVDR_DEFRANGE_FRAMEPOINTER_REL; + CVDefRangeTypeMap["subfield_reg"] = CVDR_DEFRANGE_SUBFIELD_REGISTER; + CVDefRangeTypeMap["reg_rel"] = CVDR_DEFRANGE_REGISTER_REL; +} + /// parseDirectiveCVDefRange /// ::= .cv_def_range RangeStart RangeEnd (GapStart GapEnd)*, bytes* bool AsmParser::parseDirectiveCVDefRange() { @@ -3846,13 +3889,92 @@ bool AsmParser::parseDirectiveCVDefRange() { Ranges.push_back({GapStartSym, GapEndSym}); } - std::string FixedSizePortion; - if (parseToken(AsmToken::Comma, "unexpected token in directive") || - parseEscapedString(FixedSizePortion)) - return true; - - getStreamer().EmitCVDefRangeDirective(Ranges, FixedSizePortion); - return false; + StringRef CVDefRangeTypeStr; + if (parseToken( + AsmToken::Comma, + "expected comma before def_range type in .cv_def_range directive") || + parseIdentifier(CVDefRangeTypeStr)) + return Error(Loc, "expected def_range type in directive"); + + StringMap<CVDefRangeType>::const_iterator CVTypeIt = + CVDefRangeTypeMap.find(CVDefRangeTypeStr); + CVDefRangeType CVDRType = (CVTypeIt == CVDefRangeTypeMap.end()) + ? CVDR_DEFRANGE + : CVTypeIt->getValue(); + switch (CVDRType) { + case CVDR_DEFRANGE_REGISTER: { + int64_t DRRegister; + if (parseToken(AsmToken::Comma, "expected comma before register number in " + ".cv_def_range directive") || + parseAbsoluteExpression(DRRegister)) + return Error(Loc, "expected register number"); + + codeview::DefRangeRegisterHeader DRHdr; + DRHdr.Register = DRRegister; + DRHdr.MayHaveNoName = 0; + getStreamer().EmitCVDefRangeDirective(Ranges, DRHdr); + break; + } + case CVDR_DEFRANGE_FRAMEPOINTER_REL: { + int64_t DROffset; + if (parseToken(AsmToken::Comma, + "expected comma before offset in .cv_def_range directive") || + parseAbsoluteExpression(DROffset)) + return Error(Loc, "expected offset value"); + + codeview::DefRangeFramePointerRelHeader DRHdr; + DRHdr.Offset = DROffset; + getStreamer().EmitCVDefRangeDirective(Ranges, DRHdr); + break; + } + case CVDR_DEFRANGE_SUBFIELD_REGISTER: { + int64_t DRRegister; + int64_t DROffsetInParent; + if (parseToken(AsmToken::Comma, "expected comma before register number in " + ".cv_def_range directive") || + parseAbsoluteExpression(DRRegister)) + return Error(Loc, "expected register number"); + if (parseToken(AsmToken::Comma, + "expected comma before offset in .cv_def_range directive") || + parseAbsoluteExpression(DROffsetInParent)) + return Error(Loc, "expected offset value"); + + codeview::DefRangeSubfieldRegisterHeader DRHdr; + DRHdr.Register = DRRegister; + DRHdr.MayHaveNoName = 0; + DRHdr.OffsetInParent = DROffsetInParent; + getStreamer().EmitCVDefRangeDirective(Ranges, DRHdr); + break; + } + case CVDR_DEFRANGE_REGISTER_REL: { + int64_t DRRegister; + int64_t DRFlags; + int64_t DRBasePointerOffset; + if (parseToken(AsmToken::Comma, "expected comma before register number in " + ".cv_def_range directive") || + parseAbsoluteExpression(DRRegister)) + return Error(Loc, "expected register value"); + if (parseToken( + AsmToken::Comma, + "expected comma before flag value in .cv_def_range directive") || + parseAbsoluteExpression(DRFlags)) + return Error(Loc, "expected flag value"); + if (parseToken(AsmToken::Comma, "expected comma before base pointer offset " + "in .cv_def_range directive") || + parseAbsoluteExpression(DRBasePointerOffset)) + return Error(Loc, "expected base pointer offset value"); + + codeview::DefRangeRegisterRelHeader DRHdr; + DRHdr.Register = DRRegister; + DRHdr.Flags = DRFlags; + DRHdr.BasePointerOffset = DRBasePointerOffset; + getStreamer().EmitCVDefRangeDirective(Ranges, DRHdr); + break; + } + default: + return Error(Loc, "unexpected def_range type in .cv_def_range directive"); + } + return true; } /// parseDirectiveCVString diff --git a/lib/MC/MCParser/COFFAsmParser.cpp b/lib/MC/MCParser/COFFAsmParser.cpp index 1217ea99e465..06f8310ae061 100644 --- a/lib/MC/MCParser/COFFAsmParser.cpp +++ b/lib/MC/MCParser/COFFAsmParser.cpp @@ -69,6 +69,7 @@ class COFFAsmParser : public MCAsmParserExtension { addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); // Win64 EH directives. addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>( @@ -83,21 +84,10 @@ class COFFAsmParser : public MCAsmParserExtension { ".seh_handler"); addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>( ".seh_handlerdata"); - addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>( - ".seh_pushreg"); - addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>( - ".seh_setframe"); addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>( ".seh_stackalloc"); - addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>( - ".seh_savereg"); - addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>( - ".seh_savexmm"); - addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>( - ".seh_pushframe"); addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>( ".seh_endprologue"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); } bool ParseSectionDirectiveText(StringRef, SMLoc) { @@ -143,12 +133,7 @@ class COFFAsmParser : public MCAsmParserExtension { bool ParseSEHDirectiveEndChained(StringRef, SMLoc); bool ParseSEHDirectiveHandler(StringRef, SMLoc); bool ParseSEHDirectiveHandlerData(StringRef, SMLoc); - bool ParseSEHDirectivePushReg(StringRef, SMLoc); - bool ParseSEHDirectiveSetFrame(StringRef, SMLoc); bool ParseSEHDirectiveAllocStack(StringRef, SMLoc); - bool ParseSEHDirectiveSaveReg(StringRef, SMLoc); - bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc); - bool ParseSEHDirectivePushFrame(StringRef, SMLoc); bool ParseSEHDirectiveEndProlog(StringRef, SMLoc); bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except); @@ -682,39 +667,6 @@ bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) { return false; } -bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc Loc) { - unsigned Reg = 0; - if (ParseSEHRegisterNumber(Reg)) - return true; - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - Lex(); - getStreamer().EmitWinCFIPushReg(Reg, Loc); - return false; -} - -bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc Loc) { - unsigned Reg = 0; - int64_t Off; - if (ParseSEHRegisterNumber(Reg)) - return true; - if (getLexer().isNot(AsmToken::Comma)) - return TokError("you must specify a stack pointer offset"); - - Lex(); - if (getParser().parseAbsoluteExpression(Off)) - return true; - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - Lex(); - getStreamer().EmitWinCFISetFrame(Reg, Off, Loc); - return false; -} - bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) { int64_t Size; if (getParser().parseAbsoluteExpression(Size)) @@ -728,71 +680,6 @@ bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) { return false; } -bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc Loc) { - unsigned Reg = 0; - int64_t Off; - if (ParseSEHRegisterNumber(Reg)) - return true; - if (getLexer().isNot(AsmToken::Comma)) - return TokError("you must specify an offset on the stack"); - - Lex(); - if (getParser().parseAbsoluteExpression(Off)) - return true; - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - Lex(); - // FIXME: Err on %xmm* registers - getStreamer().EmitWinCFISaveReg(Reg, Off, Loc); - return false; -} - -// FIXME: This method is inherently x86-specific. It should really be in the -// x86 backend. -bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc Loc) { - unsigned Reg = 0; - int64_t Off; - if (ParseSEHRegisterNumber(Reg)) - return true; - if (getLexer().isNot(AsmToken::Comma)) - return TokError("you must specify an offset on the stack"); - - Lex(); - if (getParser().parseAbsoluteExpression(Off)) - return true; - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - Lex(); - // FIXME: Err on non-%xmm* registers - getStreamer().EmitWinCFISaveXMM(Reg, Off, Loc); - return false; -} - -bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc Loc) { - bool Code = false; - StringRef CodeID; - if (getLexer().is(AsmToken::At)) { - SMLoc startLoc = getLexer().getLoc(); - Lex(); - if (!getParser().parseIdentifier(CodeID)) { - if (CodeID != "code") - return Error(startLoc, "expected @code"); - Code = true; - } - } - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - Lex(); - getStreamer().EmitWinCFIPushFrame(Code, Loc); - return false; -} - bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) { Lex(); getStreamer().EmitWinCFIEndProlog(Loc); @@ -816,46 +703,6 @@ bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) { return false; } -bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) { - SMLoc startLoc = getLexer().getLoc(); - if (getLexer().is(AsmToken::Percent)) { - const MCRegisterInfo *MRI = getContext().getRegisterInfo(); - SMLoc endLoc; - unsigned LLVMRegNo; - if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc)) - return true; - -#if 0 - // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering - // violation so this validation code is disabled. - - // Check that this is a non-volatile register. - const unsigned *NVRegs = TAI.getCalleeSavedRegs(); - unsigned i; - for (i = 0; NVRegs[i] != 0; ++i) - if (NVRegs[i] == LLVMRegNo) - break; - if (NVRegs[i] == 0) - return Error(startLoc, "expected non-volatile register"); -#endif - - int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo); - if (SEHRegNo < 0) - return Error(startLoc,"register can't be represented in SEH unwind info"); - RegNo = SEHRegNo; - } - else { - int64_t n; - if (getParser().parseAbsoluteExpression(n)) - return true; - if (n > 15) - return Error(startLoc, "register number is too high"); - RegNo = n; - } - - return false; -} - namespace llvm { MCAsmParserExtension *createCOFFAsmParser() { diff --git a/lib/MC/MCParser/DarwinAsmParser.cpp b/lib/MC/MCParser/DarwinAsmParser.cpp index 1160934dc62c..bd66e5f39c0d 100644 --- a/lib/MC/MCParser/DarwinAsmParser.cpp +++ b/lib/MC/MCParser/DarwinAsmParser.cpp @@ -778,8 +778,8 @@ bool DarwinAsmParser::parseDirectiveSecureLogUnique(StringRef, SMLoc IDLoc) { raw_fd_ostream *OS = getContext().getSecureLog(); if (!OS) { std::error_code EC; - auto NewOS = llvm::make_unique<raw_fd_ostream>( - StringRef(SecureLogFile), EC, sys::fs::F_Append | sys::fs::F_Text); + auto NewOS = std::make_unique<raw_fd_ostream>( + StringRef(SecureLogFile), EC, sys::fs::OF_Append | sys::fs::OF_Text); if (EC) return Error(IDLoc, Twine("can't open secure log file: ") + SecureLogFile + " (" + EC.message() + ")"); diff --git a/lib/MC/MCParser/WasmAsmParser.cpp b/lib/MC/MCParser/WasmAsmParser.cpp index 28d4459fecd4..0c242aed706d 100644 --- a/lib/MC/MCParser/WasmAsmParser.cpp +++ b/lib/MC/MCParser/WasmAsmParser.cpp @@ -123,6 +123,7 @@ public: // See use of .init_array in WasmObjectWriter and // TargetLoweringObjectFileWasm .StartsWith(".init_array", SectionKind::getData()) + .StartsWith(".debug_", SectionKind::getMetadata()) .Default(Optional<SectionKind>()); if (!Kind.hasValue()) return Parser->Error(Lexer->getLoc(), "unknown section kind: " + Name); diff --git a/lib/MC/MCRegisterInfo.cpp b/lib/MC/MCRegisterInfo.cpp index 4273b876b7bb..d491c0eb7e06 100644 --- a/lib/MC/MCRegisterInfo.cpp +++ b/lib/MC/MCRegisterInfo.cpp @@ -20,15 +20,16 @@ using namespace llvm; -unsigned MCRegisterInfo::getMatchingSuperReg(unsigned Reg, unsigned SubIdx, - const MCRegisterClass *RC) const { +MCRegister +MCRegisterInfo::getMatchingSuperReg(MCRegister Reg, unsigned SubIdx, + const MCRegisterClass *RC) const { for (MCSuperRegIterator Supers(Reg, this); Supers.isValid(); ++Supers) if (RC->contains(*Supers) && Reg == getSubReg(*Supers, SubIdx)) return *Supers; return 0; } -unsigned MCRegisterInfo::getSubReg(unsigned Reg, unsigned Idx) const { +MCRegister MCRegisterInfo::getSubReg(MCRegister Reg, unsigned Idx) const { assert(Idx && Idx < getNumSubRegIndices() && "This is not a subregister index"); // Get a pointer to the corresponding SubRegIndices list. This list has the @@ -40,7 +41,8 @@ unsigned MCRegisterInfo::getSubReg(unsigned Reg, unsigned Idx) const { return 0; } -unsigned MCRegisterInfo::getSubRegIndex(unsigned Reg, unsigned SubReg) const { +unsigned MCRegisterInfo::getSubRegIndex(MCRegister Reg, + MCRegister SubReg) const { assert(SubReg && SubReg < getNumRegs() && "This is not a register"); // Get a pointer to the corresponding SubRegIndices list. This list has the // name of each sub-register in the same order as MCSubRegIterator. @@ -63,7 +65,7 @@ unsigned MCRegisterInfo::getSubRegIdxOffset(unsigned Idx) const { return SubRegIdxRanges[Idx].Offset; } -int MCRegisterInfo::getDwarfRegNum(unsigned RegNum, bool isEH) const { +int MCRegisterInfo::getDwarfRegNum(MCRegister RegNum, bool isEH) const { const DwarfLLVMRegPair *M = isEH ? EHL2DwarfRegs : L2DwarfRegs; unsigned Size = isEH ? EHL2DwarfRegsSize : L2DwarfRegsSize; @@ -76,29 +78,18 @@ int MCRegisterInfo::getDwarfRegNum(unsigned RegNum, bool isEH) const { return I->ToReg; } -int MCRegisterInfo::getLLVMRegNum(unsigned RegNum, bool isEH) const { +Optional<unsigned> MCRegisterInfo::getLLVMRegNum(unsigned RegNum, + bool isEH) const { const DwarfLLVMRegPair *M = isEH ? EHDwarf2LRegs : Dwarf2LRegs; unsigned Size = isEH ? EHDwarf2LRegsSize : Dwarf2LRegsSize; if (!M) - return -1; - DwarfLLVMRegPair Key = { RegNum, 0 }; - const DwarfLLVMRegPair *I = std::lower_bound(M, M+Size, Key); - assert(I != M+Size && I->FromReg == RegNum && "Invalid RegNum"); - return I->ToReg; -} - -int MCRegisterInfo::getLLVMRegNumFromEH(unsigned RegNum) const { - const DwarfLLVMRegPair *M = EHDwarf2LRegs; - unsigned Size = EHDwarf2LRegsSize; - - if (!M) - return -1; + return None; DwarfLLVMRegPair Key = { RegNum, 0 }; const DwarfLLVMRegPair *I = std::lower_bound(M, M+Size, Key); - if (I == M+Size || I->FromReg != RegNum) - return -1; - return I->ToReg; + if (I != M + Size && I->FromReg == RegNum) + return I->ToReg; + return None; } int MCRegisterInfo::getDwarfRegNumFromDwarfEHRegNum(unsigned RegNum) const { @@ -110,22 +101,21 @@ int MCRegisterInfo::getDwarfRegNumFromDwarfEHRegNum(unsigned RegNum) const { // a corresponding LLVM register number at all. So if we can't map the // EH register number to an LLVM register number, assume it's just a // valid DWARF register number as is. - int LRegNum = getLLVMRegNumFromEH(RegNum); - if (LRegNum != -1) - return getDwarfRegNum(LRegNum, false); + if (Optional<unsigned> LRegNum = getLLVMRegNum(RegNum, true)) + return getDwarfRegNum(*LRegNum, false); return RegNum; } -int MCRegisterInfo::getSEHRegNum(unsigned RegNum) const { - const DenseMap<unsigned, int>::const_iterator I = L2SEHRegs.find(RegNum); +int MCRegisterInfo::getSEHRegNum(MCRegister RegNum) const { + const DenseMap<MCRegister, int>::const_iterator I = L2SEHRegs.find(RegNum); if (I == L2SEHRegs.end()) return (int)RegNum; return I->second; } -int MCRegisterInfo::getCodeViewRegNum(unsigned RegNum) const { +int MCRegisterInfo::getCodeViewRegNum(MCRegister RegNum) const { if (L2CVRegs.empty()) report_fatal_error("target does not implement codeview register mapping"); - const DenseMap<unsigned, int>::const_iterator I = L2CVRegs.find(RegNum); + const DenseMap<MCRegister, int>::const_iterator I = L2CVRegs.find(RegNum); if (I == L2CVRegs.end()) report_fatal_error("unknown codeview register " + (RegNum < getNumRegs() ? getName(RegNum) diff --git a/lib/MC/MCSectionXCOFF.cpp b/lib/MC/MCSectionXCOFF.cpp index d1a637345024..d52959f15f92 100644 --- a/lib/MC/MCSectionXCOFF.cpp +++ b/lib/MC/MCSectionXCOFF.cpp @@ -15,19 +15,65 @@ using namespace llvm; MCSectionXCOFF::~MCSectionXCOFF() = default; +static StringRef getMappingClassString(XCOFF::StorageMappingClass SMC) { + switch (SMC) { + case XCOFF::XMC_DS: + return "DS"; + case XCOFF::XMC_RW: + return "RW"; + case XCOFF::XMC_PR: + return "PR"; + default: + report_fatal_error("Unhandled storage-mapping class."); + } +} + void MCSectionXCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, raw_ostream &OS, const MCExpr *Subsection) const { if (getKind().isText()) { + if (getMappingClass() != XCOFF::XMC_PR) + report_fatal_error("Unhandled storage-mapping class for .text csect"); + OS << "\t.csect " << getSectionName() << "[" - << "PR" + << getMappingClassString(getMappingClass()) << "]" << '\n'; return; } + if (getKind().isData()) { + switch (getMappingClass()) { + case XCOFF::XMC_RW: + case XCOFF::XMC_DS: + OS << "\t.csect " << getSectionName() << "[" + << getMappingClassString(getMappingClass()) << "]" << '\n'; + break; + case XCOFF::XMC_TC0: + OS << "\t.toc\n"; + break; + default: + report_fatal_error( + "Unhandled storage-mapping class for .data csect."); + } + return; + } + + if (getKind().isBSSLocal() || getKind().isCommon()) { + assert((getMappingClass() == XCOFF::XMC_RW || + getMappingClass() == XCOFF::XMC_BS) && + "Generated a storage-mapping class for a common/bss csect we don't " + "understand how to switch to."); + assert(getCSectType() == XCOFF::XTY_CM && + "wrong csect type for .bss csect"); + // Don't have to print a directive for switching to section for commons. + // '.comm' and '.lcomm' directives for the variable will create the needed + // csect. + return; + } + report_fatal_error("Printing for this SectionKind is unimplemented."); } bool MCSectionXCOFF::UseCodeAlign() const { return getKind().isText(); } -bool MCSectionXCOFF::isVirtualSection() const { return !getKind().isCommon(); } +bool MCSectionXCOFF::isVirtualSection() const { return XCOFF::XTY_CM == Type; } diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp index decbb96817e3..b8278cb11079 100644 --- a/lib/MC/MCStreamer.cpp +++ b/lib/MC/MCStreamer.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/COFF.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeView.h" @@ -21,6 +22,8 @@ #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCRegister.h" +#include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSymbol.h" @@ -327,10 +330,56 @@ void MCStreamer::EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId, const MCSymbol *FnStartSym, const MCSymbol *FnEndSym) {} +/// Only call this on endian-specific types like ulittle16_t and little32_t, or +/// structs composed of them. +template <typename T> +static void copyBytesForDefRange(SmallString<20> &BytePrefix, + codeview::SymbolKind SymKind, + const T &DefRangeHeader) { + BytePrefix.resize(2 + sizeof(T)); + codeview::ulittle16_t SymKindLE = codeview::ulittle16_t(SymKind); + memcpy(&BytePrefix[0], &SymKindLE, 2); + memcpy(&BytePrefix[2], &DefRangeHeader, sizeof(T)); +} + void MCStreamer::EmitCVDefRangeDirective( ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, StringRef FixedSizePortion) {} +void MCStreamer::EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + codeview::DefRangeRegisterRelHeader DRHdr) { + SmallString<20> BytePrefix; + copyBytesForDefRange(BytePrefix, codeview::S_DEFRANGE_REGISTER_REL, DRHdr); + EmitCVDefRangeDirective(Ranges, BytePrefix); +} + +void MCStreamer::EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + codeview::DefRangeSubfieldRegisterHeader DRHdr) { + SmallString<20> BytePrefix; + copyBytesForDefRange(BytePrefix, codeview::S_DEFRANGE_SUBFIELD_REGISTER, + DRHdr); + EmitCVDefRangeDirective(Ranges, BytePrefix); +} + +void MCStreamer::EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + codeview::DefRangeRegisterHeader DRHdr) { + SmallString<20> BytePrefix; + copyBytesForDefRange(BytePrefix, codeview::S_DEFRANGE_REGISTER, DRHdr); + EmitCVDefRangeDirective(Ranges, BytePrefix); +} + +void MCStreamer::EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + codeview::DefRangeFramePointerRelHeader DRHdr) { + SmallString<20> BytePrefix; + copyBytesForDefRange(BytePrefix, codeview::S_DEFRANGE_FRAMEPOINTER_REL, + DRHdr); + EmitCVDefRangeDirective(Ranges, BytePrefix); +} + void MCStreamer::EmitEHSymAttributes(const MCSymbol *Symbol, MCSymbol *EHSymbol) { } @@ -631,7 +680,7 @@ void MCStreamer::EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) { MCSymbol *StartProc = EmitCFILabel(); WinFrameInfos.emplace_back( - llvm::make_unique<WinEH::FrameInfo>(Symbol, StartProc)); + std::make_unique<WinEH::FrameInfo>(Symbol, StartProc)); CurrentWinFrameInfo = WinFrameInfos.back().get(); CurrentWinFrameInfo->TextSection = getCurrentSectionOnly(); } @@ -665,7 +714,7 @@ void MCStreamer::EmitWinCFIStartChained(SMLoc Loc) { MCSymbol *StartProc = EmitCFILabel(); - WinFrameInfos.emplace_back(llvm::make_unique<WinEH::FrameInfo>( + WinFrameInfos.emplace_back(std::make_unique<WinEH::FrameInfo>( CurFrame->Function, StartProc, CurFrame)); CurrentWinFrameInfo = WinFrameInfos.back().get(); CurrentWinFrameInfo->TextSection = getCurrentSectionOnly(); @@ -763,18 +812,23 @@ MCSection *MCStreamer::getAssociatedXDataSection(const MCSection *TextSec) { void MCStreamer::EmitSyntaxDirective() {} -void MCStreamer::EmitWinCFIPushReg(unsigned Register, SMLoc Loc) { +static unsigned encodeSEHRegNum(MCContext &Ctx, MCRegister Reg) { + return Ctx.getRegisterInfo()->getSEHRegNum(Reg); +} + +void MCStreamer::EmitWinCFIPushReg(MCRegister Register, SMLoc Loc) { WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) return; MCSymbol *Label = EmitCFILabel(); - WinEH::Instruction Inst = Win64EH::Instruction::PushNonVol(Label, Register); + WinEH::Instruction Inst = Win64EH::Instruction::PushNonVol( + Label, encodeSEHRegNum(Context, Register)); CurFrame->Instructions.push_back(Inst); } -void MCStreamer::EmitWinCFISetFrame(unsigned Register, unsigned Offset, +void MCStreamer::EmitWinCFISetFrame(MCRegister Register, unsigned Offset, SMLoc Loc) { WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) @@ -790,8 +844,8 @@ void MCStreamer::EmitWinCFISetFrame(unsigned Register, unsigned Offset, MCSymbol *Label = EmitCFILabel(); - WinEH::Instruction Inst = - Win64EH::Instruction::SetFPReg(Label, Register, Offset); + WinEH::Instruction Inst = Win64EH::Instruction::SetFPReg( + Label, encodeSEHRegNum(getContext(), Register), Offset); CurFrame->LastFrameInst = CurFrame->Instructions.size(); CurFrame->Instructions.push_back(Inst); } @@ -813,7 +867,7 @@ void MCStreamer::EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) { CurFrame->Instructions.push_back(Inst); } -void MCStreamer::EmitWinCFISaveReg(unsigned Register, unsigned Offset, +void MCStreamer::EmitWinCFISaveReg(MCRegister Register, unsigned Offset, SMLoc Loc) { WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) @@ -825,12 +879,12 @@ void MCStreamer::EmitWinCFISaveReg(unsigned Register, unsigned Offset, MCSymbol *Label = EmitCFILabel(); - WinEH::Instruction Inst = - Win64EH::Instruction::SaveNonVol(Label, Register, Offset); + WinEH::Instruction Inst = Win64EH::Instruction::SaveNonVol( + Label, encodeSEHRegNum(Context, Register), Offset); CurFrame->Instructions.push_back(Inst); } -void MCStreamer::EmitWinCFISaveXMM(unsigned Register, unsigned Offset, +void MCStreamer::EmitWinCFISaveXMM(MCRegister Register, unsigned Offset, SMLoc Loc) { WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) @@ -840,8 +894,8 @@ void MCStreamer::EmitWinCFISaveXMM(unsigned Register, unsigned Offset, MCSymbol *Label = EmitCFILabel(); - WinEH::Instruction Inst = - Win64EH::Instruction::SaveXMM(Label, Register, Offset); + WinEH::Instruction Inst = Win64EH::Instruction::SaveXMM( + Label, encodeSEHRegNum(Context, Register), Offset); CurFrame->Instructions.push_back(Inst); } @@ -1009,6 +1063,10 @@ void MCStreamer::EmitCOFFSymbolStorageClass(int StorageClass) { void MCStreamer::EmitCOFFSymbolType(int Type) { llvm_unreachable("this directive only supported on COFF targets"); } +void MCStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlign) { + llvm_unreachable("this directive only supported on XCOFF targets"); +} void MCStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} void MCStreamer::emitELFSymverDirective(StringRef AliasName, const MCSymbol *Aliasee) {} diff --git a/lib/MC/MCSubtargetInfo.cpp b/lib/MC/MCSubtargetInfo.cpp index 5fd48d9e1010..c8678df02bfd 100644 --- a/lib/MC/MCSubtargetInfo.cpp +++ b/lib/MC/MCSubtargetInfo.cpp @@ -315,3 +315,28 @@ void MCSubtargetInfo::initInstrItins(InstrItineraryData &InstrItins) const { InstrItins = InstrItineraryData(getSchedModel(), Stages, OperandCycles, ForwardingPaths); } + +Optional<unsigned> MCSubtargetInfo::getCacheSize(unsigned Level) const { + return Optional<unsigned>(); +} + +Optional<unsigned> +MCSubtargetInfo::getCacheAssociativity(unsigned Level) const { + return Optional<unsigned>(); +} + +Optional<unsigned> MCSubtargetInfo::getCacheLineSize(unsigned Level) const { + return Optional<unsigned>(); +} + +unsigned MCSubtargetInfo::getPrefetchDistance() const { + return 0; +} + +unsigned MCSubtargetInfo::getMaxPrefetchIterationsAhead() const { + return UINT_MAX; +} + +unsigned MCSubtargetInfo::getMinPrefetchStride() const { + return 1; +} diff --git a/lib/MC/MCWasmObjectTargetWriter.cpp b/lib/MC/MCWasmObjectTargetWriter.cpp index e46257823e34..1ccb3a58d5c1 100644 --- a/lib/MC/MCWasmObjectTargetWriter.cpp +++ b/lib/MC/MCWasmObjectTargetWriter.cpp @@ -10,8 +10,9 @@ using namespace llvm; -MCWasmObjectTargetWriter::MCWasmObjectTargetWriter(bool Is64Bit) - : Is64Bit(Is64Bit) {} +MCWasmObjectTargetWriter::MCWasmObjectTargetWriter(bool Is64Bit, + bool IsEmscripten) + : Is64Bit(Is64Bit), IsEmscripten(IsEmscripten) {} // Pin the vtable to this object file MCWasmObjectTargetWriter::~MCWasmObjectTargetWriter() = default; diff --git a/lib/MC/MCWasmStreamer.cpp b/lib/MC/MCWasmStreamer.cpp index 86fa72197855..e7e96ecbb3a0 100644 --- a/lib/MC/MCWasmStreamer.cpp +++ b/lib/MC/MCWasmStreamer.cpp @@ -122,7 +122,7 @@ bool MCWasmStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { break; case MCSA_NoDeadStrip: - Symbol->setExported(); + Symbol->setNoStrip(); break; default: diff --git a/lib/MC/MCWinCOFFStreamer.cpp b/lib/MC/MCWinCOFFStreamer.cpp index 04d5f100a2ff..c5a21312140b 100644 --- a/lib/MC/MCWinCOFFStreamer.cpp +++ b/lib/MC/MCWinCOFFStreamer.cpp @@ -88,7 +88,19 @@ void MCWinCOFFStreamer::EmitLabel(MCSymbol *S, SMLoc Loc) { } void MCWinCOFFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { - llvm_unreachable("not implemented"); + // Let the target do whatever target specific stuff it needs to do. + getAssembler().getBackend().handleAssemblerFlag(Flag); + + switch (Flag) { + // None of these require COFF specific handling. + case MCAF_SyntaxUnified: + case MCAF_Code16: + case MCAF_Code32: + case MCAF_Code64: + break; + case MCAF_SubsectionsViaSymbols: + llvm_unreachable("COFF doesn't support .subsections_via_symbols"); + } } void MCWinCOFFStreamer::EmitThumbFunc(MCSymbol *Func) { @@ -180,7 +192,7 @@ void MCWinCOFFStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) { MCSection *SXData = getContext().getObjectFileInfo()->getSXDataSection(); getAssembler().registerSection(*SXData); if (SXData->getAlignment() < 4) - SXData->setAlignment(4); + SXData->setAlignment(Align(4)); new MCSymbolIdFragment(Symbol, SXData); @@ -197,7 +209,7 @@ void MCWinCOFFStreamer::EmitCOFFSymbolIndex(MCSymbol const *Symbol) { MCSection *Sec = getCurrentSectionOnly(); getAssembler().registerSection(*Sec); if (Sec->getAlignment() < 4) - Sec->setAlignment(4); + Sec->setAlignment(Align(4)); new MCSymbolIdFragment(Symbol, getCurrentSectionOnly()); diff --git a/lib/MC/MCXCOFFStreamer.cpp b/lib/MC/MCXCOFFStreamer.cpp index 071de024a3fa..50937d6adc0c 100644 --- a/lib/MC/MCXCOFFStreamer.cpp +++ b/lib/MC/MCXCOFFStreamer.cpp @@ -10,10 +10,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/MC/MCXCOFFStreamer.h" +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSymbolXCOFF.h" +#include "llvm/MC/MCXCOFFStreamer.h" #include "llvm/Support/TargetRegistry.h" using namespace llvm; @@ -25,14 +27,38 @@ MCXCOFFStreamer::MCXCOFFStreamer(MCContext &Context, : 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<MCSymbolXCOFF>(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, unsigned ByteAlignment) { - report_fatal_error("Emiting common symbols not implemented for XCOFF."); + getAssembler().registerSymbol(*Symbol); + Symbol->setExternal(cast<MCSymbolXCOFF>(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<MCDataFragment>(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, @@ -42,8 +68,18 @@ void MCXCOFFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, } void MCXCOFFStreamer::EmitInstToData(const MCInst &Inst, - const MCSubtargetInfo &) { - report_fatal_error("Instruction emission not implemented for XCOFF."); + const MCSubtargetInfo &STI) { + MCAssembler &Assembler = getAssembler(); + SmallVector<MCFixup, 4> 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, @@ -57,3 +93,9 @@ MCStreamer *llvm::createXCOFFStreamer(MCContext &Context, S->getAssembler().setRelaxAll(true); return S; } + +void MCXCOFFStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, + uint64_t Size, + unsigned ByteAlignment) { + EmitCommonSymbol(Symbol, Size, ByteAlignment); +} diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp index f0ceb86b25af..9f6af981aca1 100644 --- a/lib/MC/MachObjectWriter.cpp +++ b/lib/MC/MachObjectWriter.cpp @@ -25,6 +25,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolMachO.h" #include "llvm/MC/MCValue.h" +#include "llvm/Support/Alignment.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -126,7 +127,7 @@ uint64_t MachObjectWriter::getPaddingSize(const MCSection *Sec, const MCSection &NextSec = *Layout.getSectionOrder()[Next]; if (NextSec.isVirtualSection()) return 0; - return OffsetToAlignment(EndAddr, NextSec.getAlignment()); + return offsetToAlignment(EndAddr, Align(NextSec.getAlignment())); } void MachObjectWriter::writeHeader(MachO::HeaderFileType Type, @@ -444,7 +445,8 @@ void MachObjectWriter::writeLinkerOptionsLoadCommand( } // Pad to a multiple of the pointer size. - W.OS.write_zeros(OffsetToAlignment(BytesWritten, is64Bit() ? 8 : 4)); + W.OS.write_zeros( + offsetToAlignment(BytesWritten, is64Bit() ? Align(8) : Align(4))); assert(W.OS.tell() - Start == Size); } @@ -832,7 +834,8 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, // The section data is padded to 4 bytes. // // FIXME: Is this machine dependent? - unsigned SectionDataPadding = OffsetToAlignment(SectionDataFileSize, 4); + unsigned SectionDataPadding = + offsetToAlignment(SectionDataFileSize, Align(4)); SectionDataFileSize += SectionDataPadding; // Write the prolog, starting with the header and load command... @@ -997,7 +1000,8 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, #endif Asm.getLOHContainer().emit(*this, Layout); // Pad to a multiple of the pointer size. - W.OS.write_zeros(OffsetToAlignment(LOHRawSize, is64Bit() ? 8 : 4)); + W.OS.write_zeros( + offsetToAlignment(LOHRawSize, is64Bit() ? Align(8) : Align(4))); assert(W.OS.tell() - Start == LOHSize); } @@ -1043,6 +1047,6 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, std::unique_ptr<MCObjectWriter> llvm::createMachObjectWriter(std::unique_ptr<MCMachObjectTargetWriter> MOTW, raw_pwrite_stream &OS, bool IsLittleEndian) { - return llvm::make_unique<MachObjectWriter>(std::move(MOTW), OS, + return std::make_unique<MachObjectWriter>(std::move(MOTW), OS, IsLittleEndian); } diff --git a/lib/MC/StringTableBuilder.cpp b/lib/MC/StringTableBuilder.cpp index cb3db8e2268c..c9c88ec58432 100644 --- a/lib/MC/StringTableBuilder.cpp +++ b/lib/MC/StringTableBuilder.cpp @@ -38,6 +38,7 @@ void StringTableBuilder::initSize() { // 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 @@ void StringTableBuilder::write(uint8_t *Buf) const { 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/lib/MC/WasmObjectWriter.cpp b/lib/MC/WasmObjectWriter.cpp index 098343cd0107..c1ff3cc2480c 100644 --- a/lib/MC/WasmObjectWriter.cpp +++ b/lib/MC/WasmObjectWriter.cpp @@ -258,6 +258,7 @@ class WasmObjectWriter : public MCObjectWriter { // TargetObjectWriter wrappers. bool is64Bit() const { return TargetObjectWriter->is64Bit(); } + bool isEmscripten() const { return TargetObjectWriter->isEmscripten(); } void startSection(SectionBookkeeping &Section, unsigned SectionId); void startCustomSection(SectionBookkeeping &Section, StringRef Name); @@ -426,9 +427,10 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { - MCAsmBackend &Backend = Asm.getBackend(); - bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags & - MCFixupKindInfo::FKF_IsPCRel; + // The WebAssembly backend should never generate FKF_IsPCRel fixups + assert(!(Asm.getBackend().getFixupKindInfo(Fixup.getKind()).Flags & + MCFixupKindInfo::FKF_IsPCRel)); + const auto &FixupSection = cast<MCSectionWasm>(*Fragment->getParent()); uint64_t C = Target.getConstant(); uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); @@ -439,51 +441,22 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, return; if (const MCSymbolRefExpr *RefB = Target.getSymB()) { - assert(RefB->getKind() == MCSymbolRefExpr::VK_None && - "Should not have constructed this"); - - // Let A, B and C being the components of Target and R be the location of - // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). - // If it is pcrel, we want to compute (A - B + C - R). - - // In general, Wasm has no relocations for -B. It can only represent (A + C) - // or (A + C - R). If B = R + K and the relocation is not pcrel, we can - // replace B to implement it: (A - R - K + C) - if (IsPCRel) { - Ctx.reportError( - Fixup.getLoc(), - "No relocation available to represent this relative expression"); - return; - } - + // To get here the A - B expression must have failed evaluateAsRelocatable. + // This means either A or B must be undefined and in WebAssembly we can't + // support either of those cases. const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol()); - - if (SymB.isUndefined()) { - Ctx.reportError(Fixup.getLoc(), - Twine("symbol '") + SymB.getName() + - "' can not be undefined in a subtraction expression"); - return; - } - - assert(!SymB.isAbsolute() && "Should have been folded"); - const MCSection &SecB = SymB.getSection(); - if (&SecB != &FixupSection) { - Ctx.reportError(Fixup.getLoc(), - "Cannot represent a difference across sections"); - return; - } - - uint64_t SymBOffset = Layout.getSymbolOffset(SymB); - uint64_t K = SymBOffset - FixupOffset; - IsPCRel = true; - C -= K; + Ctx.reportError( + Fixup.getLoc(), + Twine("symbol '") + SymB.getName() + + "': unsupported subtraction expression used in relocation."); + return; } // We either rejected the fixup or folded B into C at this point. const MCSymbolRefExpr *RefA = Target.getSymA(); - const auto *SymA = RefA ? cast<MCSymbolWasm>(&RefA->getSymbol()) : nullptr; + const auto *SymA = cast<MCSymbolWasm>(&RefA->getSymbol()); - if (SymA && SymA->isVariable()) { + if (SymA->isVariable()) { const MCExpr *Expr = SymA->getVariableValue(); const auto *Inner = cast<MCSymbolRefExpr>(Expr); if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) @@ -496,8 +469,6 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, FixedValue = 0; unsigned Type = TargetObjectWriter->getRelocType(Target, Fixup); - assert(!IsPCRel); - assert(SymA); // Absolute offset within a section or a function. // Currently only supported for for metadata sections. @@ -1296,12 +1267,12 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // Separate out the producers and target features sections if (Name == "producers") { - ProducersSection = llvm::make_unique<WasmCustomSection>(Name, &Section); + ProducersSection = std::make_unique<WasmCustomSection>(Name, &Section); continue; } if (Name == "target_features") { TargetFeaturesSection = - llvm::make_unique<WasmCustomSection>(Name, &Section); + std::make_unique<WasmCustomSection>(Name, &Section); continue; } @@ -1379,7 +1350,9 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, report_fatal_error(".size expression must be evaluatable"); auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection()); - assert(DataSection.isWasmData()); + if (!DataSection.isWasmData()) + report_fatal_error("data symbols must live in a data section: " + + WS.getName()); // For each data symbol, export it in the symtab as a reference to the // corresponding Wasm data segment. @@ -1473,8 +1446,12 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL; if (WS.isUndefined()) Flags |= wasm::WASM_SYMBOL_UNDEFINED; - if (WS.isExported()) - Flags |= wasm::WASM_SYMBOL_EXPORTED; + if (WS.isNoStrip()) { + Flags |= wasm::WASM_SYMBOL_NO_STRIP; + if (isEmscripten()) { + Flags |= wasm::WASM_SYMBOL_EXPORTED; + } + } if (WS.getName() != WS.getImportName()) Flags |= wasm::WASM_SYMBOL_EXPLICIT_NAME; @@ -1618,5 +1595,5 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, std::unique_ptr<MCObjectWriter> llvm::createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW, raw_pwrite_stream &OS) { - return llvm::make_unique<WasmObjectWriter>(std::move(MOTW), OS); + return std::make_unique<WasmObjectWriter>(std::move(MOTW), OS); } diff --git a/lib/MC/WinCOFFObjectWriter.cpp b/lib/MC/WinCOFFObjectWriter.cpp index 0e6c05bc726d..749ed8badfaa 100644 --- a/lib/MC/WinCOFFObjectWriter.cpp +++ b/lib/MC/WinCOFFObjectWriter.cpp @@ -31,10 +31,10 @@ #include "llvm/MC/MCValue.h" #include "llvm/MC/MCWinCOFFObjectWriter.h" #include "llvm/MC/StringTableBuilder.h" +#include "llvm/Support/CRC.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/JamCRC.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" @@ -239,7 +239,7 @@ WinCOFFObjectWriter::WinCOFFObjectWriter( } COFFSymbol *WinCOFFObjectWriter::createSymbol(StringRef Name) { - Symbols.push_back(make_unique<COFFSymbol>(Name)); + Symbols.push_back(std::make_unique<COFFSymbol>(Name)); return Symbols.back().get(); } @@ -251,7 +251,7 @@ COFFSymbol *WinCOFFObjectWriter::GetOrCreateCOFFSymbol(const MCSymbol *Symbol) { } COFFSection *WinCOFFObjectWriter::createSection(StringRef Name) { - Sections.emplace_back(make_unique<COFFSection>(Name)); + Sections.emplace_back(std::make_unique<COFFSection>(Name)); return Sections.back().get(); } @@ -605,7 +605,7 @@ uint32_t WinCOFFObjectWriter::writeSectionContents(MCAssembler &Asm, // Calculate our CRC with an initial value of '0', this is not how // JamCRC is specified but it aligns with the expected output. JamCRC JC(/*Init=*/0); - JC.update(Buf); + JC.update(makeArrayRef(reinterpret_cast<uint8_t*>(Buf.data()), Buf.size())); return JC.getCRC(); } @@ -1098,5 +1098,5 @@ void MCWinCOFFObjectTargetWriter::anchor() {} std::unique_ptr<MCObjectWriter> llvm::createWinCOFFObjectWriter( std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS) { - return llvm::make_unique<WinCOFFObjectWriter>(std::move(MOTW), OS); + return std::make_unique<WinCOFFObjectWriter>(std::move(MOTW), OS); } diff --git a/lib/MC/XCOFFObjectWriter.cpp b/lib/MC/XCOFFObjectWriter.cpp index 9b9a7b6c118c..353c21068735 100644 --- a/lib/MC/XCOFFObjectWriter.cpp +++ b/lib/MC/XCOFFObjectWriter.cpp @@ -10,18 +10,135 @@ // //===----------------------------------------------------------------------===// +#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 <deque> 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(); } + 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<Symbol, 1> Syms; + StringRef getName() const { return MCCsect->getSectionName(); } + ControlSection(const MCSectionXCOFF *MCSec) + : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1), Size(0) {} +}; + +// 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; + + int16_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 CsectGroup = std::deque<ControlSection>; + 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; + + // 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; + + uint32_t SymbolTableEntryCount = 0; + uint32_t SymbolTableOffset = 0; + + virtual void reset() override; void executePostLayoutBinding(MCAssembler &, const MCAsmLayout &) override; @@ -30,6 +147,40 @@ class XCOFFObjectWriter : public MCObjectWriter { uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override; + static 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 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 + // 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 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<MCXCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS); @@ -37,11 +188,100 @@ public: XCOFFObjectWriter::XCOFFObjectWriter( std::unique_ptr<MCXCOFFObjectTargetWriter> 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(MCAssembler &Asm, + const 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<const MCSectionXCOFF *, ControlSection *> WrapperMap; + + for (const auto &S : Asm) { + const auto *MCSec = cast<const MCSectionXCOFF>(&S); + assert(WrapperMap.find(MCSec) == WrapperMap.end() && + "Cannot add a csect twice."); -void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &, - const MCAsmLayout &) { - // TODO Implement once we have sections and symbols to handle. + // 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."); + 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."); + } + } + + for (const MCSymbol &S : Asm.symbols()) { + // Nothing to do for temporary symbols. + if (S.isTemporary()) + continue; + const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(&S); + + // Map the symbol into its containing csect. + const MCSectionXCOFF *ContainingCsect = XSym->getContainingCsect(); + 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. + if (nameShouldBeInStringTable(XSym->getName())) + Strings.add(XSym->getName()); + } + + Strings.finalize(); + assignAddressesAndIndices(Layout); } void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &, @@ -50,7 +290,29 @@ void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &, 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. + 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; + } + + 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) + W.OS.write_zeros(PaddingSize); + } +} + +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. @@ -62,27 +324,274 @@ uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &) { uint64_t StartOffset = W.OS.tell(); - // TODO FIXME Assign section numbers/finalize sections. + writeFileHeader(); + writeSectionHeaderTable(); + writeSections(Asm, Layout); + // TODO writeRelocations(); - // TODO FIXME Finalize symbols. + 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<int32_t>(0); + W.write<uint32_t>(Strings.getOffset(SymbolName)); + } else { + char Name[XCOFF::NameSize]; + std::strncpy(Name, SymbolName.data(), XCOFF::NameSize); + ArrayRef<char> 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()); + assert(SymbolOffset <= UINT32_MAX - CSectionRef.Address && + "Symbol address overflows."); + W.write<uint32_t>(CSectionRef.Address + SymbolOffset); + W.write<int16_t>(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<uint16_t>(0); + W.write<uint8_t>(SymbolRef.getStorageClass()); + // Always 1 aux entry for now. + W.write<uint8_t>(1); + + // Now output the auxiliary entry. + W.write<uint32_t>(CSectionRef.SymbolTableIndex); + // Parameter typecheck hash. Not supported. + W.write<uint32_t>(0); + // Typecheck section number. Not supported. + W.write<uint16_t>(0); + // Symbol type: Label + W.write<uint8_t>(XCOFF::XTY_LD); + // Storage mapping class. + W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass()); + // Reserved (x_stab). + W.write<uint32_t>(0); + // Reserved (x_snstab). + W.write<uint16_t>(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<uint32_t>(CSectionRef.Address); + // n_scnum + W.write<int16_t>(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<uint16_t>(0); + // n_sclass + W.write<uint8_t>(StorageClass); + // Always 1 aux entry for now. + W.write<uint8_t>(1); + + // Now output the auxiliary entry. + W.write<uint32_t>(CSectionRef.Size); + // Parameter typecheck hash. Not supported. + W.write<uint32_t>(0); + // Typecheck section number. Not supported. + W.write<uint16_t>(0); + // Symbol type. + W.write<uint8_t>(getEncodedType(CSectionRef.MCCsect)); + // Storage mapping class. + W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass()); + // Reserved (x_stab). + W.write<uint32_t>(0); + // Reserved (x_snstab). + W.write<uint16_t>(0); +} + +void XCOFFObjectWriter::writeFileHeader() { // Magic. W.write<uint16_t>(0x01df); // Number of sections. - W.write<uint16_t>(0); + W.write<uint16_t>(Sections.size()); // Timestamp field. For reproducible output we write a 0, which represents no // timestamp. W.write<int32_t>(0); // Byte Offset to the start of the symbol table. - W.write<uint32_t>(0); + W.write<uint32_t>(SymbolTableOffset); // Number of entries in the symbol table. - W.write<int32_t>(0); + W.write<int32_t>(SymbolTableEntryCount); // Size of the optional header. W.write<uint16_t>(0); // Flags. W.write<uint16_t>(0); +} - return W.OS.tell() - StartOffset; +void XCOFFObjectWriter::writeSectionHeaderTable() { + for (const auto *Sec : Sections) { + // Write Name. + ArrayRef<char> 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<uint32_t>(Sec->Address); + W.write<uint32_t>(Sec->Address); + + W.write<uint32_t>(Sec->Size); + W.write<uint32_t>(Sec->FileOffsetToData); + + // Relocation pointer and Lineno pointer. Not supported yet. + W.write<uint32_t>(0); + W.write<uint32_t>(0); + + // Relocation and line-number counts. Not supported yet. + W.write<uint16_t>(0); + W.write<uint16_t>(0); + + W.write<int32_t>(Sec->Flags); + } +} + +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()); + } +} + +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; + // Section indices are 1-based in XCOFF. + 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. + 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 + 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; + + 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; + } + + 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."); + 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 @@ -90,5 +599,5 @@ uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &) { std::unique_ptr<MCObjectWriter> llvm::createXCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS) { - return llvm::make_unique<XCOFFObjectWriter>(std::move(MOTW), OS); + return std::make_unique<XCOFFObjectWriter>(std::move(MOTW), OS); } |