diff options
Diffstat (limited to 'lib/MC')
36 files changed, 1417 insertions, 674 deletions
diff --git a/lib/MC/ConstantPools.cpp b/lib/MC/ConstantPools.cpp index ca5440237e49..18277a225640 100644 --- a/lib/MC/ConstantPools.cpp +++ b/lib/MC/ConstantPools.cpp @@ -97,16 +97,14 @@ void AssemblerConstantPools::emitAll(MCStreamer &Streamer) { void AssemblerConstantPools::emitForCurrentSection(MCStreamer &Streamer) { MCSection *Section = Streamer.getCurrentSectionOnly(); - if (ConstantPool *CP = getConstantPool(Section)) { + if (ConstantPool *CP = getConstantPool(Section)) emitConstantPool(Streamer, Section, *CP); - } } void AssemblerConstantPools::clearCacheForCurrentSection(MCStreamer &Streamer) { MCSection *Section = Streamer.getCurrentSectionOnly(); - if (ConstantPool *CP = getConstantPool(Section)) { + if (ConstantPool *CP = getConstantPool(Section)) CP->clearCache(); - } } const MCExpr *AssemblerConstantPools::addEntry(MCStreamer &Streamer, diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index db531f75c87c..89f3b30cddd6 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -29,6 +29,7 @@ #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCFragment.h" +#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionELF.h" @@ -668,6 +669,20 @@ void ELFWriter::computeSymbolTable( } else { const MCSectionELF &Section = static_cast<const MCSectionELF &>(Symbol.getSection()); + + // We may end up with a situation when section symbol is technically + // defined, but should not be. That happens because we explicitly + // pre-create few .debug_* sections to have accessors. + // And if these sections were not really defined in the code, but were + // referenced, we simply error out. + if (!Section.isRegistered()) { + assert(static_cast<const MCSymbolELF &>(Symbol).getType() == + ELF::STT_SECTION); + Ctx.reportError(SMLoc(), + "Undefined section reference: " + Symbol.getName()); + continue; + } + if (Mode == NonDwoOnly && isDwoSection(Section)) continue; MSD.SectionIndex = SectionIndexMap.lookup(&Section); @@ -1107,6 +1122,8 @@ uint64_t ELFWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { SectionIndexMap[RelSection] = addToSectionTable(RelSection); Relocations.push_back(RelSection); } + + OWriter.TargetObjectWriter->addTargetSectionFlags(Ctx, Section); } MCSectionELF *CGProfileSection = nullptr; @@ -1273,6 +1290,8 @@ void ELFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, for (const MCSymbol *&Sym : AddrsigSyms) { if (const MCSymbol *R = Renames.lookup(cast<MCSymbolELF>(Sym))) Sym = R; + if (Sym->isInSection() && Sym->getName().startswith(".L")) + Sym = Sym->getSection().getBeginSymbol(); Sym->setUsedInReloc(); } } diff --git a/lib/MC/MCAsmInfoCOFF.cpp b/lib/MC/MCAsmInfoCOFF.cpp index d8fb875b67c6..15886eb619b9 100644 --- a/lib/MC/MCAsmInfoCOFF.cpp +++ b/lib/MC/MCAsmInfoCOFF.cpp @@ -25,7 +25,7 @@ MCAsmInfoCOFF::MCAsmInfoCOFF() { COMMDirectiveAlignmentIsInBytes = false; LCOMMDirectiveAlignmentType = LCOMM::ByteAlignment; HasDotTypeDotSizeDirective = false; - HasSingleParameterDotFile = false; + HasSingleParameterDotFile = true; WeakRefDirective = "\t.weak\t"; HasLinkOnceDirective = true; diff --git a/lib/MC/MCAsmInfoWasm.cpp b/lib/MC/MCAsmInfoWasm.cpp index fc55059ff75d..d448664baa14 100644 --- a/lib/MC/MCAsmInfoWasm.cpp +++ b/lib/MC/MCAsmInfoWasm.cpp @@ -15,7 +15,7 @@ #include "llvm/MC/MCAsmInfoWasm.h" using namespace llvm; -void MCAsmInfoWasm::anchor() { } +void MCAsmInfoWasm::anchor() {} MCAsmInfoWasm::MCAsmInfoWasm() { HasIdentDirective = true; diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index ae02f50bf8bd..e017103070bf 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -147,9 +147,9 @@ public: void EmitLinkerOptions(ArrayRef<std::string> Options) override; void EmitDataRegion(MCDataRegionType Kind) override; void EmitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor, - unsigned Update) override; + unsigned Update, VersionTuple SDKVersion) override; void EmitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor, - unsigned Update) override; + unsigned Update, VersionTuple SDKVersion) override; void EmitThumbFunc(MCSymbol *Func) override; void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; @@ -266,6 +266,7 @@ public: void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc L) override; void EmitIdent(StringRef IdentString) override; + void EmitCFIBKeyFrame() override; void EmitCFISections(bool EH, bool Debug) override; void EmitCFIDefCfa(int64_t Register, int64_t Offset) override; void EmitCFIDefCfaOffset(int64_t Offset) override; @@ -285,10 +286,12 @@ public: void EmitCFIUndefined(int64_t Register) override; void EmitCFIRegister(int64_t Register1, int64_t Register2) override; void EmitCFIWindowSave() override; + void EmitCFINegateRAState() override; void EmitCFIReturnColumn(int64_t Register) override; void EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) override; void EmitWinCFIEndProc(SMLoc Loc) override; + void EmitWinCFIFuncletOrFuncEnd(SMLoc Loc) override; void EmitWinCFIStartChained(SMLoc Loc) override; void EmitWinCFIEndChained(SMLoc Loc) override; void EmitWinCFIPushReg(unsigned Register, SMLoc Loc) override; @@ -513,31 +516,51 @@ static const char *getVersionMinDirective(MCVersionMinType Type) { llvm_unreachable("Invalid MC version min type"); } +static void EmitSDKVersionSuffix(raw_ostream &OS, + const VersionTuple &SDKVersion) { + if (SDKVersion.empty()) + return; + OS << '\t' << "sdk_version " << SDKVersion.getMajor(); + if (auto Minor = SDKVersion.getMinor()) { + OS << ", " << *Minor; + if (auto Subminor = SDKVersion.getSubminor()) { + OS << ", " << *Subminor; + } + } +} + void MCAsmStreamer::EmitVersionMin(MCVersionMinType Type, unsigned Major, - unsigned Minor, unsigned Update) { + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) { OS << '\t' << getVersionMinDirective(Type) << ' ' << Major << ", " << Minor; if (Update) OS << ", " << Update; + EmitSDKVersionSuffix(OS, SDKVersion); EmitEOL(); } static const char *getPlatformName(MachO::PlatformType Type) { switch (Type) { - case MachO::PLATFORM_MACOS: return "macos"; - case MachO::PLATFORM_IOS: return "ios"; - case MachO::PLATFORM_TVOS: return "tvos"; - case MachO::PLATFORM_WATCHOS: return "watchos"; - case MachO::PLATFORM_BRIDGEOS: return "bridgeos"; + case MachO::PLATFORM_MACOS: return "macos"; + case MachO::PLATFORM_IOS: return "ios"; + case MachO::PLATFORM_TVOS: return "tvos"; + case MachO::PLATFORM_WATCHOS: return "watchos"; + case MachO::PLATFORM_BRIDGEOS: return "bridgeos"; + case MachO::PLATFORM_IOSSIMULATOR: return "iossimulator"; + case MachO::PLATFORM_TVOSSIMULATOR: return "tvossimulator"; + case MachO::PLATFORM_WATCHOSSIMULATOR: return "watchossimulator"; } llvm_unreachable("Invalid Mach-O platform type"); } void MCAsmStreamer::EmitBuildVersion(unsigned Platform, unsigned Major, - unsigned Minor, unsigned Update) { + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) { const char *PlatformName = getPlatformName((MachO::PlatformType)Platform); OS << "\t.build_version " << PlatformName << ", " << Major << ", " << Minor; if (Update) OS << ", " << Update; + EmitSDKVersionSuffix(OS, SDKVersion); EmitEOL(); } @@ -858,10 +881,14 @@ void MCAsmStreamer::EmitBytes(StringRef Data) { // supported, emit as vector of 8bits data. if (Data.size() == 1 || !(MAI->getAscizDirective() || MAI->getAsciiDirective())) { - const char *Directive = MAI->getData8bitsDirective(); - for (const unsigned char C : Data.bytes()) { - OS << Directive << (unsigned)C; - EmitEOL(); + if (MCTargetStreamer *TS = getTargetStreamer()) { + TS->emitRawBytes(Data); + } else { + const char *Directive = MAI->getData8bitsDirective(); + for (const unsigned char C : Data.bytes()) { + OS << Directive << (unsigned)C; + EmitEOL(); + } } return; } @@ -1298,20 +1325,17 @@ void MCAsmStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt, StringRef FileName, SMLoc Loc) { + // Validate the directive. + if (!checkCVLocSection(FunctionId, FileNo, Loc)) + return; + OS << "\t.cv_loc\t" << FunctionId << " " << FileNo << " " << Line << " " << Column; if (PrologueEnd) OS << " prologue_end"; - unsigned OldIsStmt = getContext().getCVContext().getCurrentCVLoc().isStmt(); - if (IsStmt != OldIsStmt) { - OS << " is_stmt "; - - if (IsStmt) - OS << "1"; - else - OS << "0"; - } + if (IsStmt) + OS << " is_stmt 1"; if (IsVerboseAsm) { OS.PadToColumn(MAI->getCommentColumn()); @@ -1319,8 +1343,6 @@ void MCAsmStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, << Column; } EmitEOL(); - this->MCStreamer::EmitCVLocDirective(FunctionId, FileNo, Line, Column, - PrologueEnd, IsStmt, FileName, Loc); } void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId, @@ -1569,12 +1591,24 @@ void MCAsmStreamer::EmitCFIWindowSave() { EmitEOL(); } +void MCAsmStreamer::EmitCFINegateRAState() { + MCStreamer::EmitCFINegateRAState(); + OS << "\t.cfi_negate_ra_state"; + EmitEOL(); +} + void MCAsmStreamer::EmitCFIReturnColumn(int64_t Register) { MCStreamer::EmitCFIReturnColumn(Register); OS << "\t.cfi_return_column " << Register; EmitEOL(); } +void MCAsmStreamer::EmitCFIBKeyFrame() { + MCStreamer::EmitCFIBKeyFrame(); + OS << "\t.cfi_b_key_frame"; + EmitEOL(); +} + void MCAsmStreamer::EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) { MCStreamer::EmitWinCFIStartProc(Symbol, Loc); @@ -1590,6 +1624,10 @@ void MCAsmStreamer::EmitWinCFIEndProc(SMLoc Loc) { EmitEOL(); } +// TODO: Implement +void MCAsmStreamer::EmitWinCFIFuncletOrFuncEnd(SMLoc Loc) { +} + void MCAsmStreamer::EmitWinCFIStartChained(SMLoc Loc) { MCStreamer::EmitWinCFIStartChained(Loc); diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 1e23b6d816e8..cde6a93a1647 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -111,6 +111,7 @@ void MCAssembler::reset() { ELFHeaderEFlags = 0; LOHContainer.reset(); VersionInfo.Major = 0; + VersionInfo.SDKVersion = VersionTuple(); // reset objects owned by us if (getBackendPtr()) diff --git a/lib/MC/MCCodeView.cpp b/lib/MC/MCCodeView.cpp index 155fd7eeb576..978ac789c31e 100644 --- a/lib/MC/MCCodeView.cpp +++ b/lib/MC/MCCodeView.cpp @@ -128,6 +128,14 @@ bool CodeViewContext::recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc, return true; } +void CodeViewContext::recordCVLoc(MCContext &Ctx, const MCSymbol *Label, + unsigned FunctionId, unsigned FileNo, + unsigned Line, unsigned Column, + bool PrologueEnd, bool IsStmt) { + addLineEntry(MCCVLoc{ + Label, FunctionId, FileNo, Line, Column, PrologueEnd, IsStmt}); +} + MCDataFragment *CodeViewContext::getStringTableFragment() { if (!StrTabFragment) { StrTabFragment = new MCDataFragment(); @@ -255,7 +263,7 @@ void CodeViewContext::emitFileChecksumOffset(MCObjectStreamer &OS, OS.EmitValueImpl(SRE, 4); } -void CodeViewContext::addLineEntry(const MCCVLineEntry &LineEntry) { +void CodeViewContext::addLineEntry(const MCCVLoc &LineEntry) { size_t Offset = MCCVLines.size(); auto I = MCCVLineStartStop.insert( {LineEntry.getFunctionId(), {Offset, Offset + 1}}); @@ -264,9 +272,9 @@ void CodeViewContext::addLineEntry(const MCCVLineEntry &LineEntry) { MCCVLines.push_back(LineEntry); } -std::vector<MCCVLineEntry> +std::vector<MCCVLoc> CodeViewContext::getFunctionLineEntries(unsigned FuncId) { - std::vector<MCCVLineEntry> FilteredLines; + std::vector<MCCVLoc> FilteredLines; auto I = MCCVLineStartStop.find(FuncId); if (I != MCCVLineStartStop.end()) { MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(FuncId); @@ -289,9 +297,9 @@ CodeViewContext::getFunctionLineEntries(unsigned FuncId) { FilteredLines.back().getFileNum() != IA.File || FilteredLines.back().getLine() != IA.Line || FilteredLines.back().getColumn() != IA.Col) { - FilteredLines.push_back(MCCVLineEntry( + FilteredLines.push_back(MCCVLoc( MCCVLines[Idx].getLabel(), - MCCVLoc(FuncId, IA.File, IA.Line, IA.Col, false, false))); + FuncId, IA.File, IA.Line, IA.Col, false, false)); } } } @@ -308,7 +316,7 @@ std::pair<size_t, size_t> CodeViewContext::getLineExtent(unsigned FuncId) { return I->second; } -ArrayRef<MCCVLineEntry> CodeViewContext::getLinesForExtent(size_t L, size_t R) { +ArrayRef<MCCVLoc> CodeViewContext::getLinesForExtent(size_t L, size_t R) { if (R <= L) return None; if (L >= MCCVLines.size()) @@ -331,8 +339,8 @@ void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS, OS.EmitCOFFSectionIndex(FuncBegin); // Actual line info. - std::vector<MCCVLineEntry> Locs = getFunctionLineEntries(FuncId); - bool HaveColumns = any_of(Locs, [](const MCCVLineEntry &LineEntry) { + std::vector<MCCVLoc> Locs = getFunctionLineEntries(FuncId); + bool HaveColumns = any_of(Locs, [](const MCCVLoc &LineEntry) { return LineEntry.getColumn() != 0; }); OS.EmitIntValue(HaveColumns ? int(LF_HaveColumns) : 0, 2); @@ -342,7 +350,7 @@ void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS, // Emit a file segment for the run of locations that share a file id. unsigned CurFileNum = I->getFileNum(); auto FileSegEnd = - std::find_if(I, E, [CurFileNum](const MCCVLineEntry &Loc) { + std::find_if(I, E, [CurFileNum](const MCCVLoc &Loc) { return Loc.getFileNum() != CurFileNum; }); unsigned EntryCount = FileSegEnd - I; @@ -424,13 +432,13 @@ void CodeViewContext::emitInlineLineTableForFunction(MCObjectStreamer &OS, OS.getCurrentSectionOnly()); } -void CodeViewContext::emitDefRange( +MCFragment *CodeViewContext::emitDefRange( MCObjectStreamer &OS, ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, StringRef FixedSizePortion) { // Create and insert a fragment into the current section that will be encoded // later. - new MCCVDefRangeFragment(Ranges, FixedSizePortion, + return new MCCVDefRangeFragment(Ranges, FixedSizePortion, OS.getCurrentSectionOnly()); } @@ -468,14 +476,14 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout, if (LocBegin >= LocEnd) return; - ArrayRef<MCCVLineEntry> Locs = getLinesForExtent(LocBegin, LocEnd); + ArrayRef<MCCVLoc> Locs = getLinesForExtent(LocBegin, LocEnd); if (Locs.empty()) return; // Check that the locations are all in the same section. #ifndef NDEBUG const MCSection *FirstSec = &Locs.front().getLabel()->getSection(); - for (const MCCVLineEntry &Loc : Locs) { + for (const MCCVLoc &Loc : Locs) { if (&Loc.getLabel()->getSection() != FirstSec) { errs() << ".cv_loc " << Loc.getFunctionId() << ' ' << Loc.getFileNum() << ' ' << Loc.getLine() << ' ' << Loc.getColumn() @@ -488,7 +496,8 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout, // Make an artificial start location using the function start and the inlinee // lines start location information. All deltas start relative to this // location. - MCCVLineEntry StartLoc(Frag.getFnStartSym(), MCCVLoc(Locs.front())); + MCCVLoc StartLoc = Locs.front(); + StartLoc.setLabel(Frag.getFnStartSym()); StartLoc.setFileNum(Frag.StartFileId); StartLoc.setLine(Frag.StartLineNum); bool HaveOpenRange = false; @@ -500,7 +509,7 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout, SmallVectorImpl<char> &Buffer = Frag.getContents(); Buffer.clear(); // Clear old contents if we went through relaxation. - for (const MCCVLineEntry &Loc : Locs) { + for (const MCCVLoc &Loc : Locs) { // Exit early if our line table would produce an oversized InlineSiteSym // record. Account for the ChangeCodeLength annotation emitted after the // loop ends. @@ -585,10 +594,10 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout, unsigned EndSymLength = computeLabelDiff(Layout, LastLabel, Frag.getFnEndSym()); unsigned LocAfterLength = ~0U; - ArrayRef<MCCVLineEntry> LocAfter = getLinesForExtent(LocEnd, LocEnd + 1); + ArrayRef<MCCVLoc> LocAfter = getLinesForExtent(LocEnd, LocEnd + 1); if (!LocAfter.empty()) { // Only try to compute this difference if we're in the same section. - const MCCVLineEntry &Loc = LocAfter[0]; + const MCCVLoc &Loc = LocAfter[0]; if (&Loc.getLabel()->getSection() == &LastLabel->getSection()) LocAfterLength = computeLabelDiff(Layout, LastLabel, Loc.getLabel()); } @@ -686,31 +695,3 @@ void CodeViewContext::encodeDefRange(MCAsmLayout &Layout, } } } - -// -// This is called when an instruction is assembled into the specified section -// and if there is information from the last .cv_loc directive that has yet to have -// a line entry made for it is made. -// -void MCCVLineEntry::Make(MCObjectStreamer *MCOS) { - CodeViewContext &CVC = MCOS->getContext().getCVContext(); - if (!CVC.getCVLocSeen()) - return; - - // Create a symbol at in the current section for use in the line entry. - MCSymbol *LineSym = MCOS->getContext().createTempSymbol(); - // Set the value of the symbol to use for the MCCVLineEntry. - MCOS->EmitLabel(LineSym); - - // Get the current .loc info saved in the context. - const MCCVLoc &CVLoc = CVC.getCurrentCVLoc(); - - // Create a (local) line entry with the symbol and the current .loc info. - MCCVLineEntry LineEntry(LineSym, CVLoc); - - // clear CVLocSeen saying the current .loc info is now used. - CVC.clearCVLocSeen(); - - // Add the line entry to this section's entries. - CVC.addLineEntry(LineEntry); -} diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index 606da2526890..fab517075c5a 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -592,7 +592,7 @@ bool MCContext::isValidDwarfFileNumber(unsigned FileNumber, unsigned CUID) { return !LineTable.getMCDwarfFiles()[FileNumber].Name.empty(); } -/// Remove empty sections from SectionStartEndSyms, to avoid generating +/// Remove empty sections from SectionsForRanges, to avoid generating /// useless debug info for them. void MCContext::finalizeDwarfSections(MCStreamer &MCOS) { SectionsForRanges.remove_if( @@ -605,11 +605,6 @@ CodeViewContext &MCContext::getCVContext() { return *CVContext.get(); } -void MCContext::clearCVLocSeen() { - if (CVContext) - CVContext->clearCVLocSeen(); -} - //===----------------------------------------------------------------------===// // Error Reporting //===----------------------------------------------------------------------===// diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index 0461c2564ccf..38b02694d81d 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -463,10 +463,7 @@ MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, MakeStartMinusEndExpr(*MCOS, *LineStartSym, *LineEndSym, 4), 4); // Next 2 bytes is the Version. - // FIXME: On Darwin we still default to V2. unsigned LineTableVersion = context.getDwarfVersion(); - if (context.getObjectFileInfo()->getTargetTriple().isOSDarwin()) - LineTableVersion = 2; MCOS->EmitIntValue(LineTableVersion, 2); // Keep track of the bytes between the very start and where the header length @@ -1335,6 +1332,10 @@ void FrameEmitterImpl::EmitCFIInstruction(const MCCFIInstruction &Instr) { Streamer.EmitIntValue(dwarf::DW_CFA_GNU_window_save, 1); return; + case MCCFIInstruction::OpNegateRAState: + Streamer.EmitIntValue(dwarf::DW_CFA_AARCH64_negate_ra_state, 1); + return; + case MCCFIInstruction::OpUndefined: { unsigned Reg = Instr.getRegister(); Streamer.EmitIntValue(dwarf::DW_CFA_undefined, 1); @@ -1421,7 +1422,12 @@ void FrameEmitterImpl::EmitCFIInstruction(const MCCFIInstruction &Instr) { unsigned Reg = Instr.getRegister(); if (!IsEH) Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg); - Streamer.EmitIntValue(dwarf::DW_CFA_restore | Reg, 1); + if (Reg < 64) { + Streamer.EmitIntValue(dwarf::DW_CFA_restore | Reg, 1); + } else { + Streamer.EmitIntValue(dwarf::DW_CFA_restore_extended, 1); + Streamer.EmitULEB128IntValue(Reg); + } return; } case MCCFIInstruction::OpGnuArgsSize: @@ -1559,9 +1565,8 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(const MCDwarfFrameInfo &Frame) { uint8_t CIEVersion = getCIEVersion(IsEH, context.getDwarfVersion()); Streamer.EmitIntValue(CIEVersion, 1); - // Augmentation String - SmallString<8> Augmentation; if (IsEH) { + SmallString<8> Augmentation; Augmentation += "z"; if (Frame.Personality) Augmentation += "P"; @@ -1570,6 +1575,8 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(const MCDwarfFrameInfo &Frame) { Augmentation += "R"; if (Frame.IsSignalFrame) Augmentation += "S"; + if (Frame.IsBKeyFrame) + Augmentation += "B"; Streamer.EmitBytes(Augmentation); } Streamer.EmitIntValue(0, 1); @@ -1724,25 +1731,28 @@ namespace { struct CIEKey { static const CIEKey getEmptyKey() { - return CIEKey(nullptr, 0, -1, false, false, static_cast<unsigned>(INT_MAX)); + return CIEKey(nullptr, 0, -1, false, false, static_cast<unsigned>(INT_MAX), + false); } static const CIEKey getTombstoneKey() { - return CIEKey(nullptr, -1, 0, false, false, static_cast<unsigned>(INT_MAX)); + return CIEKey(nullptr, -1, 0, false, false, static_cast<unsigned>(INT_MAX), + false); } CIEKey(const MCSymbol *Personality, unsigned PersonalityEncoding, unsigned LSDAEncoding, bool IsSignalFrame, bool IsSimple, - unsigned RAReg) + unsigned RAReg, bool IsBKeyFrame) : Personality(Personality), PersonalityEncoding(PersonalityEncoding), LsdaEncoding(LSDAEncoding), IsSignalFrame(IsSignalFrame), - IsSimple(IsSimple), RAReg(RAReg) {} + IsSimple(IsSimple), RAReg(RAReg), IsBKeyFrame(IsBKeyFrame) {} explicit CIEKey(const MCDwarfFrameInfo &Frame) : Personality(Frame.Personality), PersonalityEncoding(Frame.PersonalityEncoding), LsdaEncoding(Frame.LsdaEncoding), IsSignalFrame(Frame.IsSignalFrame), - IsSimple(Frame.IsSimple), RAReg(Frame.RAReg) {} + IsSimple(Frame.IsSimple), RAReg(Frame.RAReg), + IsBKeyFrame(Frame.IsBKeyFrame) {} const MCSymbol *Personality; unsigned PersonalityEncoding; @@ -1750,6 +1760,7 @@ struct CIEKey { bool IsSignalFrame; bool IsSimple; unsigned RAReg; + bool IsBKeyFrame; }; } // end anonymous namespace @@ -1761,9 +1772,9 @@ template <> struct DenseMapInfo<CIEKey> { static CIEKey getTombstoneKey() { return CIEKey::getTombstoneKey(); } static unsigned getHashValue(const CIEKey &Key) { - return static_cast<unsigned>( - hash_combine(Key.Personality, Key.PersonalityEncoding, Key.LsdaEncoding, - Key.IsSignalFrame, Key.IsSimple, Key.RAReg)); + return static_cast<unsigned>(hash_combine( + Key.Personality, Key.PersonalityEncoding, Key.LsdaEncoding, + Key.IsSignalFrame, Key.IsSimple, Key.RAReg, Key.IsBKeyFrame)); } static bool isEqual(const CIEKey &LHS, const CIEKey &RHS) { @@ -1771,8 +1782,8 @@ template <> struct DenseMapInfo<CIEKey> { LHS.PersonalityEncoding == RHS.PersonalityEncoding && LHS.LsdaEncoding == RHS.LsdaEncoding && LHS.IsSignalFrame == RHS.IsSignalFrame && - LHS.IsSimple == RHS.IsSimple && - LHS.RAReg == RHS.RAReg; + LHS.IsSimple == RHS.IsSimple && LHS.RAReg == RHS.RAReg && + LHS.IsBKeyFrame == RHS.IsBKeyFrame; } }; diff --git a/lib/MC/MCELFObjectTargetWriter.cpp b/lib/MC/MCELFObjectTargetWriter.cpp index 483ee94c0db1..ff53dd7299c1 100644 --- a/lib/MC/MCELFObjectTargetWriter.cpp +++ b/lib/MC/MCELFObjectTargetWriter.cpp @@ -26,3 +26,6 @@ void MCELFObjectTargetWriter::sortRelocs(const MCAssembler &Asm, std::vector<ELFRelocationEntry> &Relocs) { } + +void MCELFObjectTargetWriter::addTargetSectionFlags(MCContext &Ctx, + MCSectionELF &Sec) {} diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp index 0694a8fa620e..3c022199145f 100644 --- a/lib/MC/MCExpr.cpp +++ b/lib/MC/MCExpr.cpp @@ -304,7 +304,9 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { case VK_Hexagon_IE: return "IE"; case VK_Hexagon_IE_GOT: return "IEGOT"; case VK_WebAssembly_FUNCTION: return "FUNCTION"; + case VK_WebAssembly_GLOBAL: return "GLOBAL"; case VK_WebAssembly_TYPEINDEX: return "TYPEINDEX"; + case VK_WebAssembly_EVENT: return "EVENT"; case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32@lo"; case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32@hi"; case VK_AMDGPU_REL32_LO: return "rel32@lo"; @@ -418,7 +420,9 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) { .Case("hi8", VK_AVR_HI8) .Case("hlo8", VK_AVR_HLO8) .Case("function", VK_WebAssembly_FUNCTION) + .Case("global", VK_WebAssembly_GLOBAL) .Case("typeindex", VK_WebAssembly_TYPEINDEX) + .Case("event", VK_WebAssembly_EVENT) .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO) .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI) .Case("rel32@lo", VK_AMDGPU_REL32_LO) @@ -524,6 +528,11 @@ static void AttemptToFoldSymbolOffsetDifference( if (Asm->isThumbFunc(&SA)) Addend |= 1; + // If symbol is labeled as micromips, we set low-bit to ensure + // correct offset in .gcc_except_table + if (Asm->getBackend().isMicroMips(&SA)) + Addend |= 1; + // Clear the symbol expr pointers to indicate we have folded these // operands. A = B = nullptr; @@ -750,8 +759,22 @@ bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, if (!ABE->getLHS()->evaluateAsRelocatableImpl(LHSValue, Asm, Layout, Fixup, Addrs, InSet) || !ABE->getRHS()->evaluateAsRelocatableImpl(RHSValue, Asm, Layout, Fixup, - Addrs, InSet)) + Addrs, InSet)) { + // Check if both are Target Expressions, see if we can compare them. + if (const MCTargetExpr *L = dyn_cast<MCTargetExpr>(ABE->getLHS())) + if (const MCTargetExpr *R = cast<MCTargetExpr>(ABE->getRHS())) { + switch (ABE->getOpcode()) { + case MCBinaryExpr::EQ: + Res = MCValue::get((L->isEqualTo(R)) ? -1 : 0); + return true; + case MCBinaryExpr::NE: + Res = MCValue::get((R->isEqualTo(R)) ? 0 : -1); + return true; + default: break; + } + } return false; + } // We only support a few operations on non-constant expressions, handle // those first. diff --git a/lib/MC/MCFragment.cpp b/lib/MC/MCFragment.cpp index 0ebcf21a422e..d22b117972bf 100644 --- a/lib/MC/MCFragment.cpp +++ b/lib/MC/MCFragment.cpp @@ -237,8 +237,8 @@ MCFragment::~MCFragment() = default; MCFragment::MCFragment(FragmentType Kind, bool HasInstructions, MCSection *Parent) - : Kind(Kind), HasInstructions(HasInstructions), Parent(Parent), - Atom(nullptr), Offset(~UINT64_C(0)) { + : Kind(Kind), HasInstructions(HasInstructions), LayoutOrder(0), + Parent(Parent), Atom(nullptr), Offset(~UINT64_C(0)) { if (Parent && !isDummy()) Parent->getFragmentList().push_back(this); } diff --git a/lib/MC/MCInst.cpp b/lib/MC/MCInst.cpp index f9b71caaf91c..64f111fc7114 100644 --- a/lib/MC/MCInst.cpp +++ b/lib/MC/MCInst.cpp @@ -72,11 +72,17 @@ void MCInst::print(raw_ostream &OS) const { void MCInst::dump_pretty(raw_ostream &OS, const MCInstPrinter *Printer, StringRef Separator) const { + StringRef InstName = Printer ? Printer->getOpcodeName(getOpcode()) : ""; + dump_pretty(OS, InstName, Separator); +} + +void MCInst::dump_pretty(raw_ostream &OS, StringRef Name, + StringRef Separator) const { OS << "<MCInst #" << getOpcode(); - // Show the instruction opcode name if we have access to a printer. - if (Printer) - OS << ' ' << Printer->getOpcodeName(getOpcode()); + // Show the instruction opcode name if we have it. + if (!Name.empty()) + OS << ' ' << Name; for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { OS << Separator; diff --git a/lib/MC/MCInstrAnalysis.cpp b/lib/MC/MCInstrAnalysis.cpp index 4d7c89116893..8223f3a5c66f 100644 --- a/lib/MC/MCInstrAnalysis.cpp +++ b/lib/MC/MCInstrAnalysis.cpp @@ -24,11 +24,6 @@ bool MCInstrAnalysis::clearsSuperRegisters(const MCRegisterInfo &MRI, return false; } -bool MCInstrAnalysis::isDependencyBreaking(const MCSubtargetInfo &STI, - const MCInst &Inst) const { - return false; -} - bool MCInstrAnalysis::evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, uint64_t &Target) const { if (Inst.getNumOperands() == 0 || diff --git a/lib/MC/MCInstrDesc.cpp b/lib/MC/MCInstrDesc.cpp index ee55f3eff3ac..53cba864a85d 100644 --- a/lib/MC/MCInstrDesc.cpp +++ b/lib/MC/MCInstrDesc.cpp @@ -39,15 +39,6 @@ bool MCInstrDesc::mayAffectControlFlow(const MCInst &MI, return false; if (hasDefOfPhysReg(MI, PC, RI)) return true; - // A variadic instruction may define PC in the variable operand list. - // There's currently no indication of which entries in a variable - // list are defs and which are uses. While that's the case, this function - // needs to assume they're defs in order to be conservatively correct. - for (int i = NumOperands, e = MI.getNumOperands(); i != e; ++i) { - if (MI.getOperand(i).isReg() && - RI.isSubRegisterEq(PC, MI.getOperand(i).getReg())) - return true; - } return false; } @@ -66,5 +57,10 @@ bool MCInstrDesc::hasDefOfPhysReg(const MCInst &MI, unsigned Reg, if (MI.getOperand(i).isReg() && RI.isSubRegisterEq(Reg, MI.getOperand(i).getReg())) return true; + if (variadicOpsAreDefs()) + for (int i = NumOperands - 1, e = MI.getNumOperands(); i != e; ++i) + if (MI.getOperand(i).isReg() && + RI.isSubRegisterEq(Reg, MI.getOperand(i).getReg())) + return true; return hasImplicitDefOfPhysReg(Reg, &RI); } diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 43e69605787c..b30317e74672 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -89,10 +89,10 @@ public: void EmitAssemblerFlag(MCAssemblerFlag Flag) override; void EmitLinkerOptions(ArrayRef<std::string> Options) override; void EmitDataRegion(MCDataRegionType Kind) override; - void EmitVersionMin(MCVersionMinType Kind, unsigned Major, - unsigned Minor, unsigned Update) override; - void EmitBuildVersion(unsigned Platform, unsigned Major, - unsigned Minor, unsigned Update) override; + void EmitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor, + unsigned Update, VersionTuple SDKVersion) override; + void EmitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor, + unsigned Update, VersionTuple SDKVersion) override; void EmitThumbFunc(MCSymbol *Func) override; bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override; @@ -270,14 +270,16 @@ void MCMachOStreamer::EmitDataRegion(MCDataRegionType Kind) { } void MCMachOStreamer::EmitVersionMin(MCVersionMinType Kind, unsigned Major, - unsigned Minor, unsigned Update) { - getAssembler().setVersionMin(Kind, Major, Minor, Update); + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) { + getAssembler().setVersionMin(Kind, Major, Minor, Update, SDKVersion); } void MCMachOStreamer::EmitBuildVersion(unsigned Platform, unsigned Major, - unsigned Minor, unsigned Update) { + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) { getAssembler().setBuildVersion((MachO::PlatformType)Platform, Major, Minor, - Update); + Update, SDKVersion); } void MCMachOStreamer::EmitThumbFunc(MCSymbol *Symbol) { @@ -507,7 +509,7 @@ MCStreamer *llvm::createMachOStreamer(MCContext &Context, new MCMachOStreamer(Context, std::move(MAB), std::move(OW), std::move(CE), DWARFMustBeAtTheEnd, LabelSections); const Triple &Target = Context.getObjectFileInfo()->getTargetTriple(); - S->EmitVersionForTarget(Target); + S->EmitVersionForTarget(Target, Context.getObjectFileInfo()->getSDKVersion()); if (RelaxAll) S->getAssembler().setRelaxAll(true); return S; diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp index a96dec184441..4e97e7550bcb 100644 --- a/lib/MC/MCNullStreamer.cpp +++ b/lib/MC/MCNullStreamer.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/StringRef.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" @@ -22,6 +23,9 @@ namespace { /// @name MCStreamer Interface /// @{ + bool hasRawTextSupport() const override { return true; } + void EmitRawTextImpl(StringRef String) override {} + bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { return true; diff --git a/lib/MC/MCObjectFileInfo.cpp b/lib/MC/MCObjectFileInfo.cpp index b88d2d801822..9e35355d06e0 100644 --- a/lib/MC/MCObjectFileInfo.cpp +++ b/lib/MC/MCObjectFileInfo.cpp @@ -63,11 +63,7 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { if (T.isWatchABI()) OmitDwarfIfHaveCompactUnwind = true; - PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel - | dwarf::DW_EH_PE_sdata4; - LSDAEncoding = FDECFIEncoding = dwarf::DW_EH_PE_pcrel; - TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_sdata4; + FDECFIEncoding = dwarf::DW_EH_PE_pcrel; // .comm doesn't support alignment before Leopard. if (T.isMacOSX() && T.isMacOSXVersionLT(10, 5)) @@ -258,9 +254,16 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { DwarfStrOffSection = Ctx->getMachOSection("__DWARF", "__debug_str_offs", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "section_str_off"); + DwarfAddrSection = + Ctx->getMachOSection("__DWARF", "__debug_addr", MachO::S_ATTR_DEBUG, + SectionKind::getMetadata(), "section_info"); DwarfLocSection = Ctx->getMachOSection("__DWARF", "__debug_loc", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "section_debug_loc"); + DwarfLoclistsSection = + Ctx->getMachOSection("__DWARF", "__debug_loclists", MachO::S_ATTR_DEBUG, + SectionKind::getMetadata(), "section_debug_loc"); + DwarfARangesSection = Ctx->getMachOSection("__DWARF", "__debug_aranges", MachO::S_ATTR_DEBUG, SectionKind::getMetadata()); @@ -295,11 +298,11 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { switch (T.getArch()) { case Triple::mips: case Triple::mipsel: - FDECFIEncoding = dwarf::DW_EH_PE_sdata4; - break; case Triple::mips64: case Triple::mips64el: - FDECFIEncoding = dwarf::DW_EH_PE_sdata8; + FDECFIEncoding = Ctx->getAsmInfo()->getCodePointerSize() == 4 + ? dwarf::DW_EH_PE_sdata4 + : dwarf::DW_EH_PE_sdata8; break; case Triple::ppc64: case Triple::ppc64le: @@ -311,158 +314,12 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { case Triple::bpfeb: FDECFIEncoding = dwarf::DW_EH_PE_sdata8; break; - default: - FDECFIEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; - break; - } - - switch (T.getArch()) { - case Triple::arm: - case Triple::armeb: - case Triple::thumb: - case Triple::thumbeb: - if (Ctx->getAsmInfo()->getExceptionHandlingType() == ExceptionHandling::ARM) - break; - // Fallthrough if not using EHABI - LLVM_FALLTHROUGH; - case Triple::ppc: - case Triple::x86: - PersonalityEncoding = PositionIndependent - ? dwarf::DW_EH_PE_indirect | - dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_sdata4 - : dwarf::DW_EH_PE_absptr; - LSDAEncoding = PositionIndependent - ? dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4 - : dwarf::DW_EH_PE_absptr; - TTypeEncoding = PositionIndependent - ? dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_sdata4 - : dwarf::DW_EH_PE_absptr; - break; - case Triple::x86_64: - if (PositionIndependent) { - PersonalityEncoding = - dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - (Large ? dwarf::DW_EH_PE_sdata8 : dwarf::DW_EH_PE_sdata4); - LSDAEncoding = dwarf::DW_EH_PE_pcrel | - (Large ? dwarf::DW_EH_PE_sdata8 : dwarf::DW_EH_PE_sdata4); - TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - (Large ? dwarf::DW_EH_PE_sdata8 : dwarf::DW_EH_PE_sdata4); - } else { - PersonalityEncoding = - Large ? dwarf::DW_EH_PE_absptr : dwarf::DW_EH_PE_udata4; - LSDAEncoding = Large ? dwarf::DW_EH_PE_absptr : dwarf::DW_EH_PE_udata4; - TTypeEncoding = Large ? dwarf::DW_EH_PE_absptr : dwarf::DW_EH_PE_udata4; - } - break; case Triple::hexagon: - PersonalityEncoding = dwarf::DW_EH_PE_absptr; - LSDAEncoding = dwarf::DW_EH_PE_absptr; - FDECFIEncoding = dwarf::DW_EH_PE_absptr; - TTypeEncoding = dwarf::DW_EH_PE_absptr; - if (PositionIndependent) { - PersonalityEncoding |= dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel; - LSDAEncoding |= dwarf::DW_EH_PE_pcrel; - FDECFIEncoding |= dwarf::DW_EH_PE_pcrel; - TTypeEncoding |= dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel; - } - break; - case Triple::aarch64: - case Triple::aarch64_be: - // The small model guarantees static code/data size < 4GB, but not where it - // will be in memory. Most of these could end up >2GB away so even a signed - // pc-relative 32-bit address is insufficient, theoretically. - if (PositionIndependent) { - PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_sdata8; - LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8; - TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_sdata8; - } else { - PersonalityEncoding = dwarf::DW_EH_PE_absptr; - LSDAEncoding = dwarf::DW_EH_PE_absptr; - TTypeEncoding = dwarf::DW_EH_PE_absptr; - } - break; - case Triple::lanai: - LSDAEncoding = dwarf::DW_EH_PE_absptr; - PersonalityEncoding = dwarf::DW_EH_PE_absptr; - TTypeEncoding = dwarf::DW_EH_PE_absptr; - break; - case Triple::mips: - case Triple::mipsel: - case Triple::mips64: - case Triple::mips64el: - // MIPS uses indirect pointer to refer personality functions and types, so - // that the eh_frame section can be read-only. DW.ref.personality will be - // generated for relocation. - PersonalityEncoding = dwarf::DW_EH_PE_indirect; - // FIXME: The N64 ABI probably ought to use DW_EH_PE_sdata8 but we can't - // identify N64 from just a triple. - TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_sdata4; - // We don't support PC-relative LSDA references in GAS so we use the default - // DW_EH_PE_absptr for those. - - // FreeBSD must be explicit about the data size and using pcrel since it's - // assembler/linker won't do the automatic conversion that the Linux tools - // do. - if (T.isOSFreeBSD()) { - PersonalityEncoding |= dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; - LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; - } - break; - case Triple::ppc64: - case Triple::ppc64le: - PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_udata8; - LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8; - TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_udata8; - break; - case Triple::sparcel: - case Triple::sparc: - if (PositionIndependent) { - LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; - PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_sdata4; - TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_sdata4; - } else { - LSDAEncoding = dwarf::DW_EH_PE_absptr; - PersonalityEncoding = dwarf::DW_EH_PE_absptr; - TTypeEncoding = dwarf::DW_EH_PE_absptr; - } - break; - case Triple::sparcv9: - LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; - if (PositionIndependent) { - PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_sdata4; - TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_sdata4; - } else { - PersonalityEncoding = dwarf::DW_EH_PE_absptr; - TTypeEncoding = dwarf::DW_EH_PE_absptr; - } - break; - case Triple::systemz: - // All currently-defined code models guarantee that 4-byte PC-relative - // values will be in range. - if (PositionIndependent) { - PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_sdata4; - LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; - TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_sdata4; - } else { - PersonalityEncoding = dwarf::DW_EH_PE_absptr; - LSDAEncoding = dwarf::DW_EH_PE_absptr; - TTypeEncoding = dwarf::DW_EH_PE_absptr; - } + FDECFIEncoding = + PositionIndependent ? dwarf::DW_EH_PE_pcrel : dwarf::DW_EH_PE_absptr; break; default: + FDECFIEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; break; } @@ -582,25 +439,26 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { Ctx->getELFSection(".debug_str_offsets", DebugSecType, 0); DwarfAddrSection = Ctx->getELFSection(".debug_addr", DebugSecType, 0); DwarfRnglistsSection = Ctx->getELFSection(".debug_rnglists", DebugSecType, 0); + DwarfLoclistsSection = Ctx->getELFSection(".debug_loclists", DebugSecType, 0); // Fission Sections DwarfInfoDWOSection = - Ctx->getELFSection(".debug_info.dwo", DebugSecType, 0); + Ctx->getELFSection(".debug_info.dwo", DebugSecType, ELF::SHF_EXCLUDE); DwarfTypesDWOSection = - Ctx->getELFSection(".debug_types.dwo", DebugSecType, 0); + Ctx->getELFSection(".debug_types.dwo", DebugSecType, ELF::SHF_EXCLUDE); DwarfAbbrevDWOSection = - Ctx->getELFSection(".debug_abbrev.dwo", DebugSecType, 0); - DwarfStrDWOSection = - Ctx->getELFSection(".debug_str.dwo", DebugSecType, - ELF::SHF_MERGE | ELF::SHF_STRINGS, 1, ""); + Ctx->getELFSection(".debug_abbrev.dwo", DebugSecType, ELF::SHF_EXCLUDE); + DwarfStrDWOSection = Ctx->getELFSection( + ".debug_str.dwo", DebugSecType, + ELF::SHF_MERGE | ELF::SHF_STRINGS | ELF::SHF_EXCLUDE, 1, ""); DwarfLineDWOSection = - Ctx->getELFSection(".debug_line.dwo", DebugSecType, 0); + Ctx->getELFSection(".debug_line.dwo", DebugSecType, ELF::SHF_EXCLUDE); DwarfLocDWOSection = - Ctx->getELFSection(".debug_loc.dwo", DebugSecType, 0); - DwarfStrOffDWOSection = - Ctx->getELFSection(".debug_str_offsets.dwo", DebugSecType, 0); + Ctx->getELFSection(".debug_loc.dwo", DebugSecType, ELF::SHF_EXCLUDE); + DwarfStrOffDWOSection = Ctx->getELFSection(".debug_str_offsets.dwo", + DebugSecType, ELF::SHF_EXCLUDE); DwarfRnglistsDWOSection = - Ctx->getELFSection(".debug_rnglists.dwo", DebugSecType, 0); + Ctx->getELFSection(".debug_rnglists.dwo", DebugSecType, ELF::SHF_EXCLUDE); // DWP Sections DwarfCUIndexSection = @@ -621,10 +479,10 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { } void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { - EHFrameSection = Ctx->getCOFFSection( - ".eh_frame", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | - COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE, - SectionKind::getData()); + EHFrameSection = + Ctx->getCOFFSection(".eh_frame", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getData()); // Set the `IMAGE_SCN_MEM_16BIT` flag when compiling for thumb mode. This is // used to indicate to the linker that the text segment contains thumb instructions @@ -652,11 +510,7 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { ".rdata", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getReadOnly()); - // FIXME: We're emitting LSDA info into a readonly section on COFF, even - // though it contains relocatable pointers. In PIC mode, this is probably a - // big runtime hit for C++ apps. Either the contents of the LSDA need to be - // adjusted or this should be a data section. - if (T.getArch() == Triple::x86_64) { + if (T.getArch() == Triple::x86_64 || T.getArch() == Triple::aarch64) { // On Windows 64 with SEH, the LSDA is emitted into the .xdata section LSDASection = nullptr; } else { @@ -893,6 +747,12 @@ void MCObjectFileInfo::initWasmMCObjectFileInfo(const Triple &T) { DwarfPubNamesSection = Ctx->getWasmSection(".debug_pubnames", SectionKind::getMetadata()); DwarfPubTypesSection = Ctx->getWasmSection(".debug_pubtypes", SectionKind::getMetadata()); + // Wasm use data section for LSDA. + // TODO Consider putting each function's exception table in a separate + // section, as in -function-sections, to facilitate lld's --gc-section. + LSDASection = Ctx->getWasmSection(".rodata.gcc_except_table", + SectionKind::getReadOnlyWithRel()); + // TODO: Define more sections. } @@ -908,8 +768,7 @@ void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, bool PIC, SupportsCompactUnwindWithoutEHFrame = false; OmitDwarfIfHaveCompactUnwind = false; - PersonalityEncoding = LSDAEncoding = FDECFIEncoding = TTypeEncoding = - dwarf::DW_EH_PE_absptr; + FDECFIEncoding = dwarf::DW_EH_PE_absptr; CompactUnwindDwarfEHFrameOnly = 0; @@ -949,16 +808,17 @@ void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, bool PIC, } } -MCSection *MCObjectFileInfo::getDwarfTypesSection(uint64_t Hash) const { +MCSection *MCObjectFileInfo::getDwarfComdatSection(const char *Name, + uint64_t Hash) const { switch (TT.getObjectFormat()) { case Triple::ELF: - return Ctx->getELFSection(".debug_types", ELF::SHT_PROGBITS, ELF::SHF_GROUP, - 0, utostr(Hash)); + return Ctx->getELFSection(Name, ELF::SHT_PROGBITS, ELF::SHF_GROUP, 0, + utostr(Hash)); case Triple::MachO: case Triple::COFF: case Triple::Wasm: case Triple::UnknownObjectFormat: - report_fatal_error("Cannot get DWARF types section for this object file " + report_fatal_error("Cannot get DWARF comdat section for this object file " "format: not implemented."); break; } diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index 4b6dad5ce8f3..6ec705bdddb7 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -59,11 +59,35 @@ void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) { PendingLabels.clear(); } +// When fixup's offset is a forward declared label, e.g.: +// +// .reloc 1f, R_MIPS_JALR, foo +// 1: nop +// +// postpone adding it to Fixups vector until the label is defined and its offset +// is known. +void MCObjectStreamer::resolvePendingFixups() { + for (PendingMCFixup &PendingFixup : PendingFixups) { + if (!PendingFixup.Sym || PendingFixup.Sym->isUndefined ()) { + getContext().reportError(PendingFixup.Fixup.getLoc(), + "unresolved relocation offset"); + continue; + } + flushPendingLabels(PendingFixup.DF, PendingFixup.DF->getContents().size()); + PendingFixup.Fixup.setOffset(PendingFixup.Sym->getOffset()); + PendingFixup.DF->getFixups().push_back(PendingFixup.Fixup); + } + PendingFixups.clear(); +} + // As a compile-time optimization, avoid allocating and evaluating an MCExpr // tree for (Hi - Lo) when Hi and Lo are offsets into the same fragment. -static Optional<uint64_t> absoluteSymbolDiff(const MCSymbol *Hi, - const MCSymbol *Lo) { +static Optional<uint64_t> +absoluteSymbolDiff(MCAssembler &Asm, const MCSymbol *Hi, const MCSymbol *Lo) { assert(Hi && Lo); + if (Asm.getBackendPtr()->requiresDiffExpressionRelocations()) + return None; + if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() || Hi->isVariable() || Lo->isVariable()) return None; @@ -74,7 +98,7 @@ static Optional<uint64_t> absoluteSymbolDiff(const MCSymbol *Hi, void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) { - if (Optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo)) { + if (Optional<uint64_t> Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) { EmitIntValue(*Diff, Size); return; } @@ -83,7 +107,7 @@ void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi, void MCObjectStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi, const MCSymbol *Lo) { - if (Optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo)) { + if (Optional<uint64_t> Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) { EmitULEB128IntValue(*Diff); return; } @@ -170,7 +194,6 @@ void MCObjectStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); - MCCVLineEntry::Make(this); MCDwarfLineEntry::Make(this, getCurrentSectionOnly()); // Avoid fixups when possible. @@ -267,7 +290,6 @@ bool MCObjectStreamer::changeSectionImpl(MCSection *Section, const MCExpr *Subsection) { assert(Section && "Cannot switch to a null section!"); flushPendingLabels(nullptr); - getContext().clearCVLocSeen(); getContext().clearDwarfLocSeen(); bool Created = getAssembler().registerSection(*Section); @@ -308,7 +330,6 @@ void MCObjectStreamer::EmitInstructionImpl(const MCInst &Inst, // Now that a machine instruction has been assembled into this section, make // a line entry for any .loc directive that has been seen. - MCCVLineEntry::Make(this); MCDwarfLineEntry::Make(this, getCurrentSectionOnly()); // If this instruction doesn't need relaxation, just emit it as data. @@ -443,12 +464,16 @@ void MCObjectStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt, StringRef FileName, SMLoc Loc) { - // In case we see two .cv_loc directives in a row, make sure the - // first one gets a line entry. - MCCVLineEntry::Make(this); + // Validate the directive. + if (!checkCVLocSection(FunctionId, FileNo, Loc)) + return; - this->MCStreamer::EmitCVLocDirective(FunctionId, FileNo, Line, Column, - PrologueEnd, IsStmt, FileName, Loc); + // Emit a label at the current position and record it in the CodeViewContext. + MCSymbol *LineSym = getContext().createTempSymbol(); + EmitLabel(LineSym); + getContext().getCVContext().recordCVLoc(getContext(), LineSym, FunctionId, + FileNo, Line, Column, PrologueEnd, + IsStmt); } void MCObjectStreamer::EmitCVLinetableDirective(unsigned FunctionId, @@ -472,7 +497,11 @@ void MCObjectStreamer::EmitCVInlineLinetableDirective( void MCObjectStreamer::EmitCVDefRangeDirective( ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, StringRef FixedSizePortion) { - getContext().getCVContext().emitDefRange(*this, Ranges, FixedSizePortion); + MCFragment *Frag = + getContext().getCVContext().emitDefRange(*this, Ranges, FixedSizePortion); + // Attach labels that were pending before we created the defrange fragment to + // the beginning of the new fragment. + flushPendingLabels(Frag, 0); this->MCStreamer::EmitCVDefRangeDirective(Ranges, FixedSizePortion); } @@ -488,11 +517,16 @@ void MCObjectStreamer::EmitCVFileChecksumOffsetDirective(unsigned FileNo) { } void MCObjectStreamer::EmitBytes(StringRef Data) { - MCCVLineEntry::Make(this); MCDwarfLineEntry::Make(this, getCurrentSectionOnly()); MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); DF->getContents().append(Data.begin(), Data.end()); + + // EmitBytes might not cover all possible ways we emit data (or could be used + // to emit executable code in some cases), but is the best method we have + // right now for checking this. + MCSection *Sec = getCurrentSectionOnly(); + Sec->setHasData(true); } void MCObjectStreamer::EmitValueToAlignment(unsigned ByteAlignment, @@ -594,16 +628,6 @@ void MCObjectStreamer::EmitGPRel64Value(const MCExpr *Value) { bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr, SMLoc Loc, const MCSubtargetInfo &STI) { - int64_t OffsetValue; - if (!Offset.evaluateAsAbsolute(OffsetValue)) - llvm_unreachable("Offset is not absolute"); - - if (OffsetValue < 0) - llvm_unreachable("Offset is negative"); - - MCDataFragment *DF = getOrCreateDataFragment(&STI); - flushPendingLabels(DF, DF->getContents().size()); - Optional<MCFixupKind> MaybeKind = Assembler->getBackend().getFixupKind(Name); if (!MaybeKind.hasValue()) return true; @@ -613,7 +637,30 @@ bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name, if (Expr == nullptr) Expr = MCSymbolRefExpr::create(getContext().createTempSymbol(), getContext()); - DF->getFixups().push_back(MCFixup::create(OffsetValue, Expr, Kind, Loc)); + + MCDataFragment *DF = getOrCreateDataFragment(&STI); + flushPendingLabels(DF, DF->getContents().size()); + + int64_t OffsetValue; + if (Offset.evaluateAsAbsolute(OffsetValue)) { + if (OffsetValue < 0) + llvm_unreachable(".reloc offset is negative"); + DF->getFixups().push_back(MCFixup::create(OffsetValue, Expr, Kind, Loc)); + return false; + } + + if (Offset.getKind() != llvm::MCExpr::SymbolRef) + llvm_unreachable(".reloc offset is not absolute nor a label"); + + const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(Offset); + if (SRE.getSymbol().isDefined()) { + DF->getFixups().push_back(MCFixup::create(SRE.getSymbol().getOffset(), + Expr, Kind, Loc)); + return false; + } + + PendingFixups.emplace_back(&SRE.getSymbol(), DF, + MCFixup::create(-1, Expr, Kind, Loc)); return false; } @@ -680,5 +727,6 @@ void MCObjectStreamer::FinishImpl() { MCDwarfLineTable::Emit(this, getAssembler().getDWARFLinetableParams()); flushPendingLabels(); + resolvePendingFixups(); getAssembler().Finish(); } diff --git a/lib/MC/MCParser/AsmLexer.cpp b/lib/MC/MCParser/AsmLexer.cpp index 74835fd70c04..2b0d20f9b8e2 100644 --- a/lib/MC/MCParser/AsmLexer.cpp +++ b/lib/MC/MCParser/AsmLexer.cpp @@ -243,22 +243,26 @@ static void SkipIgnoredIntegerSuffix(const char *&CurPtr) { // Look ahead to search for first non-hex digit, if it's [hH], then we treat the // integer as a hexadecimal, possibly with leading zeroes. -static unsigned doLookAhead(const char *&CurPtr, unsigned DefaultRadix) { - const char *FirstHex = nullptr; +static unsigned doHexLookAhead(const char *&CurPtr, unsigned DefaultRadix, + bool LexHex) { + const char *FirstNonDec = nullptr; const char *LookAhead = CurPtr; while (true) { if (isDigit(*LookAhead)) { ++LookAhead; - } else if (isHexDigit(*LookAhead)) { - if (!FirstHex) - FirstHex = LookAhead; - ++LookAhead; } else { - break; + if (!FirstNonDec) + FirstNonDec = LookAhead; + + // Keep going if we are looking for a 'h' suffix. + if (LexHex && isHexDigit(*LookAhead)) + ++LookAhead; + else + break; } } - bool isHex = *LookAhead == 'h' || *LookAhead == 'H'; - CurPtr = isHex || !FirstHex ? LookAhead : FirstHex; + bool isHex = LexHex && (*LookAhead == 'h' || *LookAhead == 'H'); + CurPtr = isHex || !FirstNonDec ? LookAhead : FirstNonDec; if (isHex) return 16; return DefaultRadix; @@ -281,7 +285,7 @@ static AsmToken intToken(StringRef Ref, APInt &Value) AsmToken AsmLexer::LexDigit() { // MASM-flavor binary integer: [01]+[bB] // MASM-flavor hexadecimal integer: [0-9][0-9a-fA-F]*[hH] - if (IsParsingMSInlineAsm && isdigit(CurPtr[-1])) { + if (LexMasmIntegers && isdigit(CurPtr[-1])) { const char *FirstNonBinary = (CurPtr[-1] != '0' && CurPtr[-1] != '1') ? CurPtr - 1 : nullptr; const char *OldCurPtr = CurPtr; @@ -320,7 +324,7 @@ AsmToken AsmLexer::LexDigit() { // Decimal integer: [1-9][0-9]* if (CurPtr[-1] != '0' || CurPtr[0] == '.') { - unsigned Radix = doLookAhead(CurPtr, 10); + unsigned Radix = doHexLookAhead(CurPtr, 10, LexMasmIntegers); bool isHex = Radix == 16; // Check for floating point literals. if (!isHex && (*CurPtr == '.' || *CurPtr == 'e')) { @@ -335,8 +339,8 @@ AsmToken AsmLexer::LexDigit() { return ReturnError(TokStart, !isHex ? "invalid decimal number" : "invalid hexdecimal number"); - // Consume the [bB][hH]. - if (Radix == 2 || Radix == 16) + // Consume the [hH]. + if (LexMasmIntegers && Radix == 16) ++CurPtr; // The darwin/x86 (and x86-64) assembler accepts and ignores type @@ -346,7 +350,7 @@ AsmToken AsmLexer::LexDigit() { return intToken(Result, Value); } - if (!IsParsingMSInlineAsm && ((*CurPtr == 'b') || (*CurPtr == 'B'))) { + if (!LexMasmIntegers && ((*CurPtr == 'b') || (*CurPtr == 'B'))) { ++CurPtr; // See if we actually have "0b" as part of something like "jmp 0b\n" if (!isDigit(CurPtr[0])) { @@ -395,7 +399,7 @@ AsmToken AsmLexer::LexDigit() { return ReturnError(TokStart, "invalid hexadecimal number"); // Consume the optional [hH]. - if (!IsParsingMSInlineAsm && (*CurPtr == 'h' || *CurPtr == 'H')) + if (LexMasmIntegers && (*CurPtr == 'h' || *CurPtr == 'H')) ++CurPtr; // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL @@ -407,7 +411,7 @@ AsmToken AsmLexer::LexDigit() { // Either octal or hexadecimal. APInt Value(128, 0, true); - unsigned Radix = doLookAhead(CurPtr, 8); + unsigned Radix = doHexLookAhead(CurPtr, 8, LexMasmIntegers); bool isHex = Radix == 16; StringRef Result(TokStart, CurPtr - TokStart); if (Result.getAsInteger(Radix, Value)) @@ -623,7 +627,6 @@ AsmToken AsmLexer::LexToken() { return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1)); case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1)); - case '-': return AsmToken(AsmToken::Minus, StringRef(TokStart, 1)); case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1)); case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1)); case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1)); @@ -642,6 +645,12 @@ AsmToken AsmLexer::LexToken() { return AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2)); } return AsmToken(AsmToken::Equal, StringRef(TokStart, 1)); + case '-': + if (*CurPtr == '>') { + ++CurPtr; + return AsmToken(AsmToken::MinusGreater, StringRef(TokStart, 2)); + } + return AsmToken(AsmToken::Minus, StringRef(TokStart, 1)); case '|': if (*CurPtr == '|') { ++CurPtr; diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 39a760826d96..cf42a6f7075b 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -180,6 +180,9 @@ private: /// Did we already inform the user about inconsistent MD5 usage? bool ReportedInconsistentMD5 = false; + // Is alt macro mode enabled. + bool AltMacroMode = false; + public: AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI, unsigned CB); @@ -226,7 +229,9 @@ public: void setParsingInlineAsm(bool V) override { ParsingInlineAsm = V; - Lexer.setParsingMSInlineAsm(V); + // When parsing MS inline asm, we must lex 0b1101 and 0ABCH as binary and + // hex integer literals. + Lexer.setLexMasmIntegers(V); } bool isParsingInlineAsm() override { return ParsingInlineAsm; } @@ -260,8 +265,6 @@ public: /// } private: - bool isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc); - void altMacroString(StringRef AltMacroStr, std::string &Res); bool parseStatement(ParseStatementInfo &Info, MCAsmParserSemaCallback *SI); bool parseCurlyBlockScope(SmallVectorImpl<AsmRewrite>& AsmStrRewrites); @@ -337,7 +340,7 @@ private: StringRef parseStringToComma(); bool parseAssignment(StringRef Name, bool allow_redef, - bool NoDeadStrip = false, bool AllowExtendedExpr = false); + bool NoDeadStrip = false); unsigned getBinOpPrecedence(AsmToken::TokenKind K, MCBinaryExpr::Opcode &Kind); @@ -467,6 +470,7 @@ private: DK_CV_INLINE_LINETABLE, DK_CV_DEF_RANGE, DK_CV_STRINGTABLE, + DK_CV_STRING, DK_CV_FILECHECKSUMS, DK_CV_FILECHECKSUM_OFFSET, DK_CV_FPO_DATA, @@ -491,6 +495,7 @@ private: DK_CFI_UNDEFINED, DK_CFI_REGISTER, DK_CFI_WINDOW_SAVE, + DK_CFI_B_KEY_FRAME, DK_MACROS_ON, DK_MACROS_OFF, DK_ALTMACRO, @@ -538,7 +543,7 @@ private: bool parseDirectiveStabs(); // ".cv_file", ".cv_func_id", ".cv_inline_site_id", ".cv_loc", ".cv_linetable", - // ".cv_inline_linetable", ".cv_def_range" + // ".cv_inline_linetable", ".cv_def_range", ".cv_string" bool parseDirectiveCVFile(); bool parseDirectiveCVFuncId(); bool parseDirectiveCVInlineSiteId(); @@ -546,6 +551,7 @@ private: bool parseDirectiveCVLinetable(); bool parseDirectiveCVInlineLinetable(); bool parseDirectiveCVDefRange(); + bool parseDirectiveCVString(); bool parseDirectiveCVStringTable(); bool parseDirectiveCVFileChecksums(); bool parseDirectiveCVFileChecksumOffset(); @@ -670,6 +676,7 @@ namespace llvm { extern MCAsmParserExtension *createDarwinAsmParser(); extern MCAsmParserExtension *createELFAsmParser(); extern MCAsmParserExtension *createCOFFAsmParser(); +extern MCAsmParserExtension *createWasmAsmParser(); } // end namespace llvm @@ -700,10 +707,7 @@ AsmParser::AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, PlatformParser.reset(createELFAsmParser()); break; case MCObjectFileInfo::IsWasm: - // TODO: WASM will need its own MCAsmParserExtension implementation, but - // for now we can re-use the ELF one, since the directives can be the - // same for now. - PlatformParser.reset(createELFAsmParser()); + PlatformParser.reset(createWasmAsmParser()); break; } @@ -895,6 +899,9 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { eatToEndOfStatement(); } + getTargetParser().onEndOfFile(); + printPendingErrors(); + // All errors should have been emitted. assert(!hasPendingError() && "unexpected error from parseStatement"); @@ -1100,7 +1107,7 @@ bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { // This is a symbol reference. StringRef SymbolName = Identifier; if (SymbolName.empty()) - return true; + return Error(getLexer().getLoc(), "expected a symbol reference"); MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; @@ -1123,7 +1130,7 @@ bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { // semantics in the face of reassignment. if (Sym->isVariable()) { auto V = Sym->getVariableValue(/*SetUsed*/ false); - bool DoInline = isa<MCConstantExpr>(V); + bool DoInline = isa<MCConstantExpr>(V) && !Variant; if (auto TV = dyn_cast<MCTargetExpr>(V)) DoInline = TV->inlineAssignedExpr(); if (DoInline) { @@ -1321,11 +1328,12 @@ AsmParser::applyModifierToExpr(const MCExpr *E, /// the End argument will be filled with the last location pointed to the '>' /// character. -/// There is a gap between the AltMacro's documentation and the single quote implementation. -/// GCC does not fully support this feature and so we will not support it. +/// There is a gap between the AltMacro's documentation and the single quote +/// implementation. GCC does not fully support this feature and so we will not +/// support it. /// TODO: Adding single quote as a string. -bool AsmParser::isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc) { - assert((StrLoc.getPointer() != NULL) && +static bool isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc) { + assert((StrLoc.getPointer() != nullptr) && "Argument to the function cannot be a NULL value"); const char *CharPtr = StrLoc.getPointer(); while ((*CharPtr != '>') && (*CharPtr != '\n') && (*CharPtr != '\r') && @@ -1342,12 +1350,14 @@ bool AsmParser::isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc) { } /// creating a string without the escape characters '!'. -void AsmParser::altMacroString(StringRef AltMacroStr,std::string &Res) { +static std::string altMacroString(StringRef AltMacroStr) { + std::string Res; for (size_t Pos = 0; Pos < AltMacroStr.size(); Pos++) { if (AltMacroStr[Pos] == '!') Pos++; Res += AltMacroStr[Pos]; } + return Res; } /// Parse an expression and return it. @@ -1363,7 +1373,8 @@ void AsmParser::altMacroString(StringRef AltMacroStr,std::string &Res) { bool AsmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc) { // Parse the expression. Res = nullptr; - if (parsePrimaryExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc)) + if (getTargetParser().parsePrimaryExpr(Res, EndLoc) || + parseBinOpRHS(1, Res, EndLoc)) return true; // As a special case, we support 'a op b @ modifier' by rewriting the @@ -1617,7 +1628,7 @@ bool AsmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, // Eat the next primary expression. const MCExpr *RHS; - if (parsePrimaryExpr(RHS, EndLoc)) + if (getTargetParser().parsePrimaryExpr(RHS, EndLoc)) return true; // If BinOp binds less tightly with RHS than the operator after RHS, let @@ -1805,6 +1816,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, Lex(); } + getTargetParser().doBeforeLabelEmit(Sym); + // Emit the label. if (!getTargetParser().isParsingInlineAsm()) Out.EmitLabel(Sym, IDLoc); @@ -1826,7 +1839,7 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, // identifier '=' ... -> assignment statement Lex(); - return parseAssignment(IDVal, true, /*NoDeadStrip*/ false, /*AllowExtendedExpr*/true); + return parseAssignment(IDVal, true); default: // Normal instruction or directive. break; @@ -1841,7 +1854,7 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, // Otherwise, we have a normal instruction or directive. // Directives start with "." - if (IDVal[0] == '.' && IDVal != ".") { + if (IDVal.startswith(".") && IDVal != ".") { // There are several entities interested in parsing directives: // // 1. The target-specific assembly parser. Some directives are target @@ -2028,6 +2041,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, return parseDirectiveCVInlineLinetable(); case DK_CV_DEF_RANGE: return parseDirectiveCVDefRange(); + case DK_CV_STRING: + return parseDirectiveCVString(); case DK_CV_STRINGTABLE: return parseDirectiveCVStringTable(); case DK_CV_FILECHECKSUMS: @@ -2430,21 +2445,20 @@ bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, for (const AsmToken &Token : A[Index]) // For altmacro mode, you can write '%expr'. // The prefix '%' evaluates the expression 'expr' - // and uses the result as a string (e.g. replace %(1+2) with the string "3"). + // and uses the result as a string (e.g. replace %(1+2) with the + // string "3"). // Here, we identify the integer token which is the result of the - // absolute expression evaluation and replace it with its string representation. - if ((Lexer.IsaAltMacroMode()) && - (*(Token.getString().begin()) == '%') && Token.is(AsmToken::Integer)) + // absolute expression evaluation and replace it with its string + // representation. + if (AltMacroMode && Token.getString().front() == '%' && + Token.is(AsmToken::Integer)) // Emit an integer value to the buffer. OS << Token.getIntVal(); // Only Token that was validated as a string and begins with '<' // is considered altMacroString!!! - else if ((Lexer.IsaAltMacroMode()) && - (*(Token.getString().begin()) == '<') && + else if (AltMacroMode && Token.getString().front() == '<' && Token.is(AsmToken::String)) { - std::string Res; - altMacroString(Token.getStringContents(), Res); - OS << Res; + OS << altMacroString(Token.getStringContents()); } // We expect no quotes around the string's contents when // parsing for varargs. @@ -2626,31 +2640,33 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M, SMLoc StrLoc = Lexer.getLoc(); SMLoc EndLoc; - if (Lexer.IsaAltMacroMode() && Lexer.is(AsmToken::Percent)) { - const MCExpr *AbsoluteExp; - int64_t Value; - /// Eat '%' - Lex(); - if (parseExpression(AbsoluteExp, EndLoc)) - return false; - if (!AbsoluteExp->evaluateAsAbsolute(Value, - getStreamer().getAssemblerPtr())) - return Error(StrLoc, "expected absolute expression"); - const char *StrChar = StrLoc.getPointer(); - const char *EndChar = EndLoc.getPointer(); - AsmToken newToken(AsmToken::Integer, StringRef(StrChar , EndChar - StrChar), Value); - FA.Value.push_back(newToken); - } else if (Lexer.IsaAltMacroMode() && Lexer.is(AsmToken::Less) && + if (AltMacroMode && Lexer.is(AsmToken::Percent)) { + const MCExpr *AbsoluteExp; + int64_t Value; + /// Eat '%' + Lex(); + if (parseExpression(AbsoluteExp, EndLoc)) + return false; + if (!AbsoluteExp->evaluateAsAbsolute(Value, + getStreamer().getAssemblerPtr())) + return Error(StrLoc, "expected absolute expression"); + const char *StrChar = StrLoc.getPointer(); + const char *EndChar = EndLoc.getPointer(); + AsmToken newToken(AsmToken::Integer, + StringRef(StrChar, EndChar - StrChar), Value); + FA.Value.push_back(newToken); + } else if (AltMacroMode && Lexer.is(AsmToken::Less) && isAltmacroString(StrLoc, EndLoc)) { - const char *StrChar = StrLoc.getPointer(); - const char *EndChar = EndLoc.getPointer(); - jumpToLoc(EndLoc, CurBuffer); - /// Eat from '<' to '>' - Lex(); - AsmToken newToken(AsmToken::String, StringRef(StrChar, EndChar - StrChar)); - FA.Value.push_back(newToken); + const char *StrChar = StrLoc.getPointer(); + const char *EndChar = EndLoc.getPointer(); + jumpToLoc(EndLoc, CurBuffer); + /// Eat from '<' to '>' + Lex(); + AsmToken newToken(AsmToken::String, + StringRef(StrChar, EndChar - StrChar)); + FA.Value.push_back(newToken); } else if(parseMacroArgument(FA.Value, Vararg)) - return true; + return true; unsigned PI = Parameter; if (!FA.Name.empty()) { @@ -2766,11 +2782,11 @@ void AsmParser::handleMacroExit() { } bool AsmParser::parseAssignment(StringRef Name, bool allow_redef, - bool NoDeadStrip, bool AllowExtendedExpr) { + bool NoDeadStrip) { MCSymbol *Sym; const MCExpr *Value; if (MCParserUtils::parseAssignmentExpression(Name, allow_redef, *this, Sym, - Value, AllowExtendedExpr)) + Value)) return true; if (!Sym) { @@ -2926,20 +2942,20 @@ bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) { bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) { const MCExpr *Offset; const MCExpr *Expr = nullptr; - - SMLoc OffsetLoc = Lexer.getTok().getLoc(); int64_t OffsetValue; - // We can only deal with constant expressions at the moment. + SMLoc OffsetLoc = Lexer.getTok().getLoc(); if (parseExpression(Offset)) return true; - if (check(!Offset->evaluateAsAbsolute(OffsetValue, - getStreamer().getAssemblerPtr()), - OffsetLoc, "expression is not a constant value") || - check(OffsetValue < 0, OffsetLoc, "expression is negative") || - parseToken(AsmToken::Comma, "expected comma") || - check(getTok().isNot(AsmToken::Identifier), "expected relocation name")) + if ((Offset->evaluateAsAbsolute(OffsetValue, + getStreamer().getAssemblerPtr()) && + check(OffsetValue < 0, OffsetLoc, "expression is negative")) || + (check(Offset->getKind() != llvm::MCExpr::Constant && + Offset->getKind() != llvm::MCExpr::SymbolRef, + OffsetLoc, "expected non-negative number or a label")) || + (parseToken(AsmToken::Comma, "expected comma") || + check(getTok().isNot(AsmToken::Identifier), "expected relocation name"))) return true; SMLoc NameLoc = Lexer.getTok().getLoc(); @@ -3347,17 +3363,20 @@ bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) { } } - // In case there is a -g option as well as debug info from directive .file, - // we turn off the -g option, directly use the existing debug info instead. - // Also reset any implicit ".file 0" for the assembler source. - if (Ctx.getGenDwarfForAssembly()) { - Ctx.getMCDwarfLineTable(0).resetRootFile(); - Ctx.setGenDwarfForAssembly(false); - } - - if (FileNumber == -1) + if (FileNumber == -1) { + if (!getContext().getAsmInfo()->hasSingleParameterDotFile()) + return Error(DirectiveLoc, + "target does not support '.file' without a number"); getStreamer().EmitFileDirective(Filename); - else { + } else { + // In case there is a -g option as well as debug info from directive .file, + // we turn off the -g option, directly use the existing debug info instead. + // Also reset any implicit ".file 0" for the assembler source. + if (Ctx.getGenDwarfForAssembly()) { + Ctx.getMCDwarfLineTable(0).resetRootFile(); + Ctx.setGenDwarfForAssembly(false); + } + MD5::MD5Result *CKMem = nullptr; if (HasMD5) { CKMem = (MD5::MD5Result *)Ctx.allocate(sizeof(MD5::MD5Result), 1); @@ -3812,6 +3831,20 @@ bool AsmParser::parseDirectiveCVDefRange() { return false; } +/// parseDirectiveCVString +/// ::= .cv_stringtable "string" +bool AsmParser::parseDirectiveCVString() { + std::string Data; + if (checkForValidSection() || parseEscapedString(Data)) + return addErrorSuffix(" in '.cv_string' directive"); + + // Put the string in the table and emit the offset. + std::pair<StringRef, unsigned> Insertion = + getCVContext().addToStringTable(Data); + getStreamer().EmitIntValue(Insertion.second, 4); + return false; +} + /// parseDirectiveCVStringTable /// ::= .cv_stringtable bool AsmParser::parseDirectiveCVStringTable() { @@ -3894,7 +3927,12 @@ bool AsmParser::parseDirectiveCFIStartProc() { return addErrorSuffix(" in '.cfi_startproc' directive"); } - getStreamer().EmitCFIStartProc(!Simple.empty()); + // TODO(kristina): Deal with a corner case of incorrect diagnostic context + // being produced if this directive is emitted as part of preprocessor macro + // expansion which can *ONLY* happen if Clang's cc1as is the API consumer. + // Tools like llvm-mc on the other hand are not affected by it, and report + // correct context information. + getStreamer().EmitCFIStartProc(!Simple.empty(), Lexer.getLoc()); return false; } @@ -4162,10 +4200,7 @@ bool AsmParser::parseDirectiveCFIUndefined(SMLoc DirectiveLoc) { bool AsmParser::parseDirectiveAltmacro(StringRef Directive) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '" + Directive + "' directive"); - if (Directive == ".altmacro") - getLexer().SetAltMacroMode(true); - else - getLexer().SetAltMacroMode(false); + AltMacroMode = (Directive == ".altmacro"); return false; } @@ -5237,6 +5272,7 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".cv_inline_linetable"] = DK_CV_INLINE_LINETABLE; DirectiveKindMap[".cv_inline_site_id"] = DK_CV_INLINE_SITE_ID; DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE; + DirectiveKindMap[".cv_string"] = DK_CV_STRING; DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE; DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS; DirectiveKindMap[".cv_filechecksumoffset"] = DK_CV_FILECHECKSUM_OFFSET; @@ -5264,6 +5300,7 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED; DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER; DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE; + DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME; DirectiveKindMap[".macros_on"] = DK_MACROS_ON; DirectiveKindMap[".macros_off"] = DK_MACROS_OFF; DirectiveKindMap[".macro"] = DK_MACRO; @@ -5839,17 +5876,12 @@ static bool isSymbolUsedInExpression(const MCSymbol *Sym, const MCExpr *Value) { bool parseAssignmentExpression(StringRef Name, bool allow_redef, MCAsmParser &Parser, MCSymbol *&Sym, - const MCExpr *&Value, bool AllowExtendedExpr) { + const MCExpr *&Value) { // FIXME: Use better location, we should use proper tokens. SMLoc EqualLoc = Parser.getTok().getLoc(); - SMLoc EndLoc; - if (AllowExtendedExpr) { - if (Parser.getTargetParser().parseAssignmentExpression(Value, EndLoc)) { - return Parser.TokError("missing expression"); - } - } else if (Parser.parseExpression(Value, EndLoc)) - return Parser.TokError("missing expression"); + if (Parser.parseExpression(Value)) + return Parser.TokError("missing expression"); // Note: we don't count b as used in "a = b". This is to allow // a = b diff --git a/lib/MC/MCParser/CMakeLists.txt b/lib/MC/MCParser/CMakeLists.txt index 99fdd0167993..0c54e8e90193 100644 --- a/lib/MC/MCParser/CMakeLists.txt +++ b/lib/MC/MCParser/CMakeLists.txt @@ -8,6 +8,7 @@ add_llvm_library(LLVMMCParser MCAsmParser.cpp MCAsmParserExtension.cpp MCTargetAsmParser.cpp + WasmAsmParser.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/MC/MCParser diff --git a/lib/MC/MCParser/DarwinAsmParser.cpp b/lib/MC/MCParser/DarwinAsmParser.cpp index e6fc1fac81ba..cd99112292a9 100644 --- a/lib/MC/MCParser/DarwinAsmParser.cpp +++ b/lib/MC/MCParser/DarwinAsmParser.cpp @@ -459,7 +459,12 @@ public: bool parseBuildVersion(StringRef Directive, SMLoc Loc); bool parseVersionMin(StringRef Directive, SMLoc Loc, MCVersionMinType Type); + bool parseMajorMinorVersionComponent(unsigned *Major, unsigned *Minor, + const char *VersionName); + bool parseOptionalTrailingVersionComponent(unsigned *Component, + const char *ComponentName); bool parseVersion(unsigned *Major, unsigned *Minor, unsigned *Update); + bool parseSDKVersion(VersionTuple &SDKVersion); void checkVersion(StringRef Directive, StringRef Arg, SMLoc Loc, Triple::OSType ExpectedOS); }; @@ -1000,43 +1005,89 @@ bool DarwinAsmParser::parseDirectiveDataRegionEnd(StringRef, SMLoc) { return false; } -/// parseVersion ::= major, minor [, update] -bool DarwinAsmParser::parseVersion(unsigned *Major, unsigned *Minor, - unsigned *Update) { +static bool isSDKVersionToken(const AsmToken &Tok) { + return Tok.is(AsmToken::Identifier) && Tok.getIdentifier() == "sdk_version"; +} + +/// parseMajorMinorVersionComponent ::= major, minor +bool DarwinAsmParser::parseMajorMinorVersionComponent(unsigned *Major, + unsigned *Minor, + const char *VersionName) { // Get the major version number. if (getLexer().isNot(AsmToken::Integer)) - return TokError("invalid OS major version number, integer expected"); + return TokError(Twine("invalid ") + VersionName + + " major version number, integer expected"); int64_t MajorVal = getLexer().getTok().getIntVal(); if (MajorVal > 65535 || MajorVal <= 0) - return TokError("invalid OS major version number"); + return TokError(Twine("invalid ") + VersionName + " major version number"); *Major = (unsigned)MajorVal; Lex(); if (getLexer().isNot(AsmToken::Comma)) - return TokError("OS minor version number required, comma expected"); + return TokError(Twine(VersionName) + + " minor version number required, comma expected"); Lex(); // Get the minor version number. if (getLexer().isNot(AsmToken::Integer)) - return TokError("invalid OS minor version number, integer expected"); + return TokError(Twine("invalid ") + VersionName + + " minor version number, integer expected"); int64_t MinorVal = getLexer().getTok().getIntVal(); if (MinorVal > 255 || MinorVal < 0) - return TokError("invalid OS minor version number"); + return TokError(Twine("invalid ") + VersionName + " minor version number"); *Minor = MinorVal; Lex(); + return false; +} + +/// parseOptionalTrailingVersionComponent ::= , version_number +bool DarwinAsmParser::parseOptionalTrailingVersionComponent( + unsigned *Component, const char *ComponentName) { + assert(getLexer().is(AsmToken::Comma) && "comma expected"); + Lex(); + if (getLexer().isNot(AsmToken::Integer)) + return TokError(Twine("invalid ") + ComponentName + + " version number, integer expected"); + int64_t Val = getLexer().getTok().getIntVal(); + if (Val > 255 || Val < 0) + return TokError(Twine("invalid ") + ComponentName + " version number"); + *Component = Val; + Lex(); + return false; +} + +/// parseVersion ::= parseMajorMinorVersionComponent +/// parseOptionalTrailingVersionComponent +bool DarwinAsmParser::parseVersion(unsigned *Major, unsigned *Minor, + unsigned *Update) { + if (parseMajorMinorVersionComponent(Major, Minor, "OS")) + return true; // Get the update level, if specified *Update = 0; - if (getLexer().is(AsmToken::EndOfStatement)) + if (getLexer().is(AsmToken::EndOfStatement) || + isSDKVersionToken(getLexer().getTok())) return false; if (getLexer().isNot(AsmToken::Comma)) return TokError("invalid OS update specifier, comma expected"); + if (parseOptionalTrailingVersionComponent(Update, "OS update")) + return true; + return false; +} + +bool DarwinAsmParser::parseSDKVersion(VersionTuple &SDKVersion) { + assert(isSDKVersionToken(getLexer().getTok()) && "expected sdk_version"); Lex(); - if (getLexer().isNot(AsmToken::Integer)) - return TokError("invalid OS update version number, integer expected"); - int64_t UpdateVal = getLexer().getTok().getIntVal(); - if (UpdateVal > 255 || UpdateVal < 0) - return TokError("invalid OS update version number"); - *Update = UpdateVal; - Lex(); + unsigned Major, Minor; + if (parseMajorMinorVersionComponent(&Major, &Minor, "SDK")) + return true; + SDKVersion = VersionTuple(Major, Minor); + + // Get the subminor version, if specified. + if (getLexer().is(AsmToken::Comma)) { + unsigned Subminor; + if (parseOptionalTrailingVersionComponent(&Subminor, "SDK subminor")) + return true; + SDKVersion = VersionTuple(Major, Minor, Subminor); + } return false; } @@ -1066,10 +1117,10 @@ static Triple::OSType getOSTypeFromMCVM(MCVersionMinType Type) { } /// parseVersionMin -/// ::= .ios_version_min parseVersion -/// | .macosx_version_min parseVersion -/// | .tvos_version_min parseVersion -/// | .watchos_version_min parseVersion +/// ::= .ios_version_min parseVersion parseSDKVersion +/// | .macosx_version_min parseVersion parseSDKVersion +/// | .tvos_version_min parseVersion parseSDKVersion +/// | .watchos_version_min parseVersion parseSDKVersion bool DarwinAsmParser::parseVersionMin(StringRef Directive, SMLoc Loc, MCVersionMinType Type) { unsigned Major; @@ -1078,13 +1129,16 @@ bool DarwinAsmParser::parseVersionMin(StringRef Directive, SMLoc Loc, if (parseVersion(&Major, &Minor, &Update)) return true; + VersionTuple SDKVersion; + if (isSDKVersionToken(getLexer().getTok()) && parseSDKVersion(SDKVersion)) + return true; + if (parseToken(AsmToken::EndOfStatement)) return addErrorSuffix(Twine(" in '") + Directive + "' directive"); Triple::OSType ExpectedOS = getOSTypeFromMCVM(Type); checkVersion(Directive, StringRef(), Loc, ExpectedOS); - - getStreamer().EmitVersionMin(Type, Major, Minor, Update); + getStreamer().EmitVersionMin(Type, Major, Minor, Update, SDKVersion); return false; } @@ -1094,13 +1148,16 @@ static Triple::OSType getOSTypeFromPlatform(MachO::PlatformType Type) { case MachO::PLATFORM_IOS: return Triple::IOS; case MachO::PLATFORM_TVOS: return Triple::TvOS; case MachO::PLATFORM_WATCHOS: return Triple::WatchOS; - case MachO::PLATFORM_BRIDGEOS: /* silence warning */break; + case MachO::PLATFORM_BRIDGEOS: /* silence warning */ break; + case MachO::PLATFORM_IOSSIMULATOR: /* silence warning */ break; + case MachO::PLATFORM_TVOSSIMULATOR: /* silence warning */ break; + case MachO::PLATFORM_WATCHOSSIMULATOR: /* silence warning */ break; } llvm_unreachable("Invalid mach-o platform type"); } /// parseBuildVersion -/// ::= .build_version (macos|ios|tvos|watchos), parseVersion +/// ::= .build_version (macos|ios|tvos|watchos), parseVersion parseSDKVersion bool DarwinAsmParser::parseBuildVersion(StringRef Directive, SMLoc Loc) { StringRef PlatformName; SMLoc PlatformLoc = getTok().getLoc(); @@ -1126,14 +1183,17 @@ bool DarwinAsmParser::parseBuildVersion(StringRef Directive, SMLoc Loc) { if (parseVersion(&Major, &Minor, &Update)) return true; + VersionTuple SDKVersion; + if (isSDKVersionToken(getLexer().getTok()) && parseSDKVersion(SDKVersion)) + return true; + if (parseToken(AsmToken::EndOfStatement)) return addErrorSuffix(" in '.build_version' directive"); Triple::OSType ExpectedOS = getOSTypeFromPlatform((MachO::PlatformType)Platform); checkVersion(Directive, PlatformName, Loc, ExpectedOS); - - getStreamer().EmitBuildVersion(Platform, Major, Minor, Update); + getStreamer().EmitBuildVersion(Platform, Major, Minor, Update, SDKVersion); return false; } diff --git a/lib/MC/MCParser/ELFAsmParser.cpp b/lib/MC/MCParser/ELFAsmParser.cpp index 7bf14968c973..d568f7a71eeb 100644 --- a/lib/MC/MCParser/ELFAsmParser.cpp +++ b/lib/MC/MCParser/ELFAsmParser.cpp @@ -321,6 +321,9 @@ static unsigned parseSectionFlags(StringRef flagsStr, bool *UseLastGroup) { case 'y': flags |= ELF::SHF_ARM_PURECODE; break; + case 's': + flags |= ELF::SHF_HEX_GPREL; + break; case 'G': flags |= ELF::SHF_GROUP; break; @@ -481,34 +484,6 @@ static bool hasPrefix(StringRef SectionName, StringRef Prefix) { return SectionName.startswith(Prefix) || SectionName == Prefix.drop_back(); } -// Return a set of section flags based on the section name that can then -// be augmented later, otherwise return 0 if we don't have any reasonable -// defaults. -static unsigned defaultSectionFlags(StringRef SectionName) { - - if (hasPrefix(SectionName, ".rodata.cst")) - return ELF::SHF_ALLOC | ELF::SHF_MERGE; - - if (hasPrefix(SectionName, ".rodata.") || SectionName == ".rodata1") - return ELF::SHF_ALLOC; - - if (SectionName == ".fini" || SectionName == ".init" || - hasPrefix(SectionName, ".text.")) - return ELF::SHF_ALLOC | ELF::SHF_EXECINSTR; - - if (hasPrefix(SectionName, ".data.") || SectionName == ".data1" || - hasPrefix(SectionName, ".bss.") || - hasPrefix(SectionName, ".init_array.") || - hasPrefix(SectionName, ".fini_array.") || - hasPrefix(SectionName, ".preinit_array.")) - return ELF::SHF_ALLOC | ELF::SHF_WRITE; - - if (hasPrefix(SectionName, ".tdata.") || hasPrefix(SectionName, ".tbss.")) - return ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_TLS; - - return 0; -} - bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) { StringRef SectionName; @@ -518,13 +493,27 @@ bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) { StringRef TypeName; int64_t Size = 0; StringRef GroupName; + unsigned Flags = 0; const MCExpr *Subsection = nullptr; bool UseLastGroup = false; MCSymbolELF *Associated = nullptr; int64_t UniqueID = ~0; - // Set the default section flags first in case no others are given. - unsigned Flags = defaultSectionFlags(SectionName); + // Set the defaults first. + if (hasPrefix(SectionName, ".rodata.") || SectionName == ".rodata1") + Flags |= ELF::SHF_ALLOC; + else if (SectionName == ".fini" || SectionName == ".init" || + hasPrefix(SectionName, ".text.")) + Flags |= ELF::SHF_ALLOC | ELF::SHF_EXECINSTR; + else if (hasPrefix(SectionName, ".data.") || SectionName == ".data1" || + hasPrefix(SectionName, ".bss.") || + hasPrefix(SectionName, ".init_array.") || + hasPrefix(SectionName, ".fini_array.") || + hasPrefix(SectionName, ".preinit_array.")) + Flags |= ELF::SHF_ALLOC | ELF::SHF_WRITE; + else if (hasPrefix(SectionName, ".tdata.") || + hasPrefix(SectionName, ".tbss.")) + Flags |= ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_TLS; if (getLexer().is(AsmToken::Comma)) { Lex(); @@ -552,12 +541,6 @@ bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) { if (extraFlags == -1U) return TokError("unknown flag"); - - // If we found additional section flags on a known section then give a - // warning. - if (Flags && Flags != extraFlags) - Warning(loc, "setting incorrect section attributes for " + SectionName); - Flags |= extraFlags; bool Mergeable = Flags & ELF::SHF_MERGE; diff --git a/lib/MC/MCParser/MCAsmLexer.cpp b/lib/MC/MCParser/MCAsmLexer.cpp index 75cd318e4fa3..10960fc69633 100644 --- a/lib/MC/MCParser/MCAsmLexer.cpp +++ b/lib/MC/MCParser/MCAsmLexer.cpp @@ -15,7 +15,7 @@ using namespace llvm; -MCAsmLexer::MCAsmLexer() : AltMacroMode(false) { +MCAsmLexer::MCAsmLexer() { CurTok.emplace_back(AsmToken::Space, StringRef()); } @@ -85,6 +85,7 @@ void AsmToken::dump(raw_ostream &OS) const { case AsmToken::LessGreater: OS << "LessGreater"; break; case AsmToken::LessLess: OS << "LessLess"; break; case AsmToken::Minus: OS << "Minus"; break; + case AsmToken::MinusGreater: OS << "MinusGreater"; break; case AsmToken::Percent: OS << "Percent"; break; case AsmToken::Pipe: OS << "Pipe"; break; case AsmToken::PipePipe: OS << "PipePipe"; break; diff --git a/lib/MC/MCParser/MCAsmParser.cpp b/lib/MC/MCParser/MCAsmParser.cpp index d439734e76fc..efedcdc5a314 100644 --- a/lib/MC/MCParser/MCAsmParser.cpp +++ b/lib/MC/MCParser/MCAsmParser.cpp @@ -21,7 +21,7 @@ using namespace llvm; -MCAsmParser::MCAsmParser() : ShowParsedOperands(0) {} +MCAsmParser::MCAsmParser() {} MCAsmParser::~MCAsmParser() = default; diff --git a/lib/MC/MCParser/WasmAsmParser.cpp b/lib/MC/MCParser/WasmAsmParser.cpp new file mode 100644 index 000000000000..93bb0cb3c72e --- /dev/null +++ b/lib/MC/MCParser/WasmAsmParser.cpp @@ -0,0 +1,145 @@ +//===- WasmAsmParser.cpp - Wasm Assembly Parser -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// -- +// +// Note, this is for wasm, the binary format (analogous to ELF), not wasm, +// the instruction set (analogous to x86), for which parsing code lives in +// WebAssemblyAsmParser. +// +// This file contains processing for generic directives implemented using +// MCTargetStreamer, the ones that depend on WebAssemblyTargetStreamer are in +// WebAssemblyAsmParser. +// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/Wasm.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCSymbolWasm.h" +#include "llvm/Support/MachineValueType.h" + +using namespace llvm; + +namespace { + +class WasmAsmParser : public MCAsmParserExtension { + MCAsmParser *Parser; + MCAsmLexer *Lexer; + + template<bool (WasmAsmParser::*HandlerMethod)(StringRef, SMLoc)> + void addDirectiveHandler(StringRef Directive) { + MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( + this, HandleDirective<WasmAsmParser, HandlerMethod>); + + getParser().addDirectiveHandler(Directive, Handler); + } + +public: + WasmAsmParser() : Parser(nullptr), Lexer(nullptr) { + BracketExpressionsSupported = true; + } + + void Initialize(MCAsmParser &P) override { + Parser = &P; + Lexer = &Parser->getLexer(); + // Call the base implementation. + this->MCAsmParserExtension::Initialize(*Parser); + + addDirectiveHandler<&WasmAsmParser::parseSectionDirectiveText>(".text"); + addDirectiveHandler<&WasmAsmParser::parseSectionDirective>(".section"); + addDirectiveHandler<&WasmAsmParser::parseDirectiveSize>(".size"); + addDirectiveHandler<&WasmAsmParser::parseDirectiveType>(".type"); + } + + bool Error(const StringRef &msg, const AsmToken &tok) { + return Parser->Error(tok.getLoc(), msg + tok.getString()); + } + + bool IsNext(AsmToken::TokenKind Kind) { + auto ok = Lexer->is(Kind); + if (ok) Lex(); + return ok; + } + + bool Expect(AsmToken::TokenKind Kind, const char *KindName) { + if (!IsNext(Kind)) + return Error(std::string("Expected ") + KindName + ", instead got: ", + Lexer->getTok()); + return false; + } + + bool parseSectionDirectiveText(StringRef, SMLoc) { + // FIXME: .text currently no-op. + return false; + } + + bool parseSectionDirective(StringRef, SMLoc) { + // FIXME: .section currently no-op. + while (Lexer->isNot(AsmToken::EndOfStatement)) Parser->Lex(); + return false; + } + + // TODO: This function is almost the same as ELFAsmParser::ParseDirectiveSize + // so maybe could be shared somehow. + bool parseDirectiveSize(StringRef, SMLoc) { + StringRef Name; + if (Parser->parseIdentifier(Name)) + return TokError("expected identifier in directive"); + auto Sym = getContext().getOrCreateSymbol(Name); + if (Lexer->isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + const MCExpr *Expr; + if (Parser->parseExpression(Expr)) + return true; + if (Lexer->isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + Lex(); + // MCWasmStreamer implements this. + getStreamer().emitELFSize(Sym, Expr); + return false; + } + + bool parseDirectiveType(StringRef, SMLoc) { + // This could be the start of a function, check if followed by + // "label,@function" + if (!Lexer->is(AsmToken::Identifier)) + return Error("Expected label after .type directive, got: ", + Lexer->getTok()); + auto WasmSym = cast<MCSymbolWasm>( + getStreamer().getContext().getOrCreateSymbol( + Lexer->getTok().getString())); + Lex(); + if (!(IsNext(AsmToken::Comma) && IsNext(AsmToken::At) && + Lexer->is(AsmToken::Identifier))) + return Error("Expected label,@type declaration, got: ", Lexer->getTok()); + auto TypeName = Lexer->getTok().getString(); + if (TypeName == "function") + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); + else if (TypeName == "global") + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); + else + return Error("Unknown WASM symbol type: ", Lexer->getTok()); + Lex(); + return Expect(AsmToken::EndOfStatement, "EOL"); + } +}; + +} // end anonymous namespace + +namespace llvm { + +MCAsmParserExtension *createWasmAsmParser() { + return new WasmAsmParser; +} + +} // end namespace llvm diff --git a/lib/MC/MCRegisterInfo.cpp b/lib/MC/MCRegisterInfo.cpp index 8e47963b4418..5abae5379867 100644 --- a/lib/MC/MCRegisterInfo.cpp +++ b/lib/MC/MCRegisterInfo.cpp @@ -13,6 +13,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/ErrorHandling.h" #include <algorithm> #include <cassert> @@ -127,6 +128,8 @@ int MCRegisterInfo::getCodeViewRegNum(unsigned RegNum) const { report_fatal_error("target does not implement codeview register mapping"); const DenseMap<unsigned, int>::const_iterator I = L2CVRegs.find(RegNum); if (I == L2CVRegs.end()) - report_fatal_error("unknown codeview register"); + report_fatal_error("unknown codeview register " + (RegNum < getNumRegs() + ? getName(RegNum) + : Twine(RegNum))); return I->second; } diff --git a/lib/MC/MCSection.cpp b/lib/MC/MCSection.cpp index 97bc65387dd5..d4f11d10136a 100644 --- a/lib/MC/MCSection.cpp +++ b/lib/MC/MCSection.cpp @@ -23,7 +23,8 @@ using namespace llvm; MCSection::MCSection(SectionVariant V, SectionKind K, MCSymbol *Begin) : Begin(Begin), BundleGroupBeforeFirstInst(false), HasInstructions(false), - IsRegistered(false), DummyFragment(this), Variant(V), Kind(K) {} + HasData(false), IsRegistered(false), DummyFragment(this), Variant(V), + Kind(K) {} MCSymbol *MCSection::getEndSymbol(MCContext &Ctx) { if (!End) diff --git a/lib/MC/MCSectionELF.cpp b/lib/MC/MCSectionELF.cpp index 4d77d05cc505..7ee1694ebbf7 100644 --- a/lib/MC/MCSectionELF.cpp +++ b/lib/MC/MCSectionELF.cpp @@ -116,6 +116,9 @@ void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, } else if (T.isARM() || T.isThumb()) { if (Flags & ELF::SHF_ARM_PURECODE) OS << 'y'; + } else if (Arch == Triple::hexagon) { + if (Flags & ELF::SHF_HEX_GPREL) + OS << 's'; } OS << '"'; diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp index 21a9c3604cfc..6a8471bc61b4 100644 --- a/lib/MC/MCStreamer.cpp +++ b/lib/MC/MCStreamer.cpp @@ -72,6 +72,18 @@ void MCTargetStreamer::emitValue(const MCExpr *Value) { Streamer.EmitRawText(OS.str()); } +void MCTargetStreamer::emitRawBytes(StringRef Data) { + const MCAsmInfo *MAI = Streamer.getContext().getAsmInfo(); + const char *Directive = MAI->getData8bitsDirective(); + for (const unsigned char C : Data.bytes()) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + + OS << Directive << (unsigned)C; + Streamer.EmitRawText(OS.str()); + } +} + void MCTargetStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {} MCStreamer::MCStreamer(MCContext &Ctx) @@ -209,6 +221,13 @@ void MCStreamer::emitDwarfFile0Directive(StringRef Directory, Source); } +void MCStreamer::EmitCFIBKeyFrame() { + MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; + CurFrame->IsBKeyFrame = true; +} + void MCStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column, unsigned Flags, unsigned Isa, @@ -270,22 +289,28 @@ bool MCStreamer::EmitCVInlineSiteIdDirective(unsigned FunctionId, void MCStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt, - StringRef FileName, SMLoc Loc) { + StringRef FileName, SMLoc Loc) {} + +bool MCStreamer::checkCVLocSection(unsigned FuncId, unsigned FileNo, + SMLoc Loc) { CodeViewContext &CVC = getContext().getCVContext(); - MCCVFunctionInfo *FI = CVC.getCVFunctionInfo(FunctionId); - if (!FI) - return getContext().reportError( + MCCVFunctionInfo *FI = CVC.getCVFunctionInfo(FuncId); + if (!FI) { + getContext().reportError( Loc, "function id not introduced by .cv_func_id or .cv_inline_site_id"); + return false; + } // Track the section if (FI->Section == nullptr) FI->Section = getCurrentSectionOnly(); - else if (FI->Section != getCurrentSectionOnly()) - return getContext().reportError( + else if (FI->Section != getCurrentSectionOnly()) { + getContext().reportError( Loc, "all .cv_loc directives for a function must be in the same section"); - - CVC.setCurrentCVLoc(FunctionId, FileNo, Line, Column, PrologueEnd, IsStmt); + return false; + } + return true; } void MCStreamer::EmitCVLinetableDirective(unsigned FunctionId, @@ -341,10 +366,10 @@ void MCStreamer::EmitCFISections(bool EH, bool Debug) { assert(EH || Debug); } -void MCStreamer::EmitCFIStartProc(bool IsSimple) { +void MCStreamer::EmitCFIStartProc(bool IsSimple, SMLoc Loc) { if (hasUnfinishedDwarfFrameInfo()) - getContext().reportError( - SMLoc(), "starting new .cfi frame before finishing the previous one"); + return getContext().reportError( + Loc, "starting new .cfi frame before finishing the previous one"); MCDwarfFrameInfo Frame; Frame.IsSimple = IsSimple; @@ -559,6 +584,15 @@ void MCStreamer::EmitCFIWindowSave() { CurFrame->Instructions.push_back(Instruction); } +void MCStreamer::EmitCFINegateRAState() { + MCSymbol *Label = EmitCFILabel(); + MCCFIInstruction Instruction = MCCFIInstruction::createNegateRAState(Label); + MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; + CurFrame->Instructions.push_back(Instruction); +} + void MCStreamer::EmitCFIReturnColumn(int64_t Register) { MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); if (!CurFrame) @@ -609,6 +643,17 @@ void MCStreamer::EmitWinCFIEndProc(SMLoc Loc) { CurFrame->End = Label; } +void MCStreamer::EmitWinCFIFuncletOrFuncEnd(SMLoc Loc) { + WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); + if (!CurFrame) + return; + if (CurFrame->ChainedParent) + getContext().reportError(Loc, "Not all chained regions terminated!"); + + MCSymbol *Label = EmitCFILabel(); + CurFrame->FuncletOrFuncEnd = Label; +} + void MCStreamer::EmitWinCFIStartChained(SMLoc Loc) { WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) @@ -820,13 +865,11 @@ void MCStreamer::EmitWinCFIEndProlog(SMLoc Loc) { CurFrame->PrologEnd = Label; } -void MCStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) { -} +void MCStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) {} void MCStreamer::EmitCOFFSymbolIndex(MCSymbol const *Symbol) {} -void MCStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) { -} +void MCStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) {} void MCStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) {} @@ -836,9 +879,12 @@ void MCStreamer::EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) {} /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. void MCStreamer::EmitRawTextImpl(StringRef String) { - errs() << "EmitRawText called on an MCStreamer that doesn't support it, " - " something must not be fully mc'ized\n"; - abort(); + // This is not llvm_unreachable for the sake of out of tree backend + // developers who may not have assembly streamers and should serve as a + // reminder to not accidentally call EmitRawText in the absence of such. + report_fatal_error("EmitRawText called on an MCStreamer that doesn't support " + "it (target backend is likely missing an AsmStreamer " + "implementation)"); } void MCStreamer::EmitRawText(const Twine &T) { @@ -872,8 +918,9 @@ void MCStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { TS->emitAssignment(Symbol, Value); } -void MCTargetStreamer::prettyPrintAsm(MCInstPrinter &InstPrinter, raw_ostream &OS, - const MCInst &Inst, const MCSubtargetInfo &STI) { +void MCTargetStreamer::prettyPrintAsm(MCInstPrinter &InstPrinter, + raw_ostream &OS, const MCInst &Inst, + const MCSubtargetInfo &STI) { InstPrinter.printInst(&Inst, OS, "", STI); } @@ -1016,7 +1063,8 @@ MCSymbol *MCStreamer::endSection(MCSection *Section) { return Sym; } -void MCStreamer::EmitVersionForTarget(const Triple &Target) { +void MCStreamer::EmitVersionForTarget(const Triple &Target, + const VersionTuple &SDKVersion) { if (!Target.isOSBinFormatMachO() || !Target.isOSDarwin()) return; // Do we even know the version? @@ -1042,5 +1090,5 @@ void MCStreamer::EmitVersionForTarget(const Triple &Target) { Target.getiOSVersion(Major, Minor, Update); } if (Major != 0) - EmitVersionMin(VersionType, Major, Minor, Update); + EmitVersionMin(VersionType, Major, Minor, Update, SDKVersion); } diff --git a/lib/MC/MCWasmStreamer.cpp b/lib/MC/MCWasmStreamer.cpp index 0e5932214047..d2a152058b90 100644 --- a/lib/MC/MCWasmStreamer.cpp +++ b/lib/MC/MCWasmStreamer.cpp @@ -61,7 +61,7 @@ void MCWasmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { void MCWasmStreamer::ChangeSection(MCSection *Section, const MCExpr *Subsection) { MCAssembler &Asm = getAssembler(); - auto *SectionWasm = static_cast<const MCSectionWasm *>(Section); + auto *SectionWasm = cast<MCSectionWasm>(Section); const MCSymbol *Grp = SectionWasm->getGroup(); if (Grp) Asm.registerSymbol(*Grp); @@ -119,7 +119,6 @@ bool MCWasmStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { break; case MCSA_ELF_TypeObject: - Symbol->setType(wasm::WASM_SYMBOL_TYPE_DATA); break; default: diff --git a/lib/MC/MCWin64EH.cpp b/lib/MC/MCWin64EH.cpp index 1407f25e6f2a..0724b109e1a1 100644 --- a/lib/MC/MCWin64EH.cpp +++ b/lib/MC/MCWin64EH.cpp @@ -11,6 +11,9 @@ #include "llvm/ADT/Twine.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/Win64EH.h" @@ -23,6 +26,8 @@ static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) { uint8_t Count = 0; for (const auto &I : Insns) { switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) { + default: + llvm_unreachable("Unsupported unwind code"); case Win64EH::UOP_PushNonVol: case Win64EH::UOP_AllocSmall: case Win64EH::UOP_SetFPReg: @@ -60,6 +65,8 @@ static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, uint16_t w; b2 = (inst.Operation & 0x0F); switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) { + default: + llvm_unreachable("Unsupported unwind code"); case Win64EH::UOP_PushNonVol: EmitAbsDifference(streamer, inst.Label, begin); b2 |= (inst.Register & 0x0F) << 4; @@ -242,3 +249,348 @@ void llvm::Win64EH::UnwindEmitter::EmitUnwindInfo( ::EmitUnwindInfo(Streamer, info); } +static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, + const MCSymbol *RHS) { + MCContext &Context = Streamer.getContext(); + const MCExpr *Diff = + MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context), + MCSymbolRefExpr::create(RHS, Context), Context); + MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer); + int64_t value; + Diff->evaluateAsAbsolute(value, OS->getAssembler()); + return value; +} + +static uint32_t +ARM64CountOfUnwindCodes(const std::vector<WinEH::Instruction> &Insns) { + uint32_t Count = 0; + for (const auto &I : Insns) { + switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) { + default: + llvm_unreachable("Unsupported ARM64 unwind code"); + case Win64EH::UOP_AllocSmall: + Count += 1; + break; + case Win64EH::UOP_AllocMedium: + Count += 2; + break; + case Win64EH::UOP_AllocLarge: + Count += 4; + break; + case Win64EH::UOP_SaveFPLRX: + Count += 1; + break; + case Win64EH::UOP_SaveFPLR: + Count += 1; + break; + case Win64EH::UOP_SaveReg: + Count += 2; + break; + case Win64EH::UOP_SaveRegP: + Count += 2; + break; + case Win64EH::UOP_SaveRegPX: + Count += 2; + break; + case Win64EH::UOP_SaveRegX: + Count += 2; + break; + case Win64EH::UOP_SaveFReg: + Count += 2; + break; + case Win64EH::UOP_SaveFRegP: + Count += 2; + break; + case Win64EH::UOP_SaveFRegX: + Count += 2; + break; + case Win64EH::UOP_SaveFRegPX: + Count += 2; + break; + case Win64EH::UOP_SetFP: + Count += 1; + break; + case Win64EH::UOP_AddFP: + Count += 2; + break; + case Win64EH::UOP_Nop: + Count += 1; + break; + case Win64EH::UOP_End: + Count += 1; + break; + } + } + return Count; +} + +// Unwind opcode encodings and restrictions are documented at +// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling +static void ARM64EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, + WinEH::Instruction &inst) { + uint8_t b, reg; + switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) { + default: + llvm_unreachable("Unsupported ARM64 unwind code"); + case Win64EH::UOP_AllocSmall: + b = (inst.Offset >> 4) & 0x1F; + streamer.EmitIntValue(b, 1); + break; + case Win64EH::UOP_AllocMedium: { + uint16_t hw = (inst.Offset >> 4) & 0x7FF; + b = 0xC0; + b |= (hw >> 8); + streamer.EmitIntValue(b, 1); + b = hw & 0xFF; + streamer.EmitIntValue(b, 1); + break; + } + case Win64EH::UOP_AllocLarge: { + uint32_t w; + b = 0xE0; + streamer.EmitIntValue(b, 1); + w = inst.Offset >> 4; + b = (w & 0x00FF0000) >> 16; + streamer.EmitIntValue(b, 1); + b = (w & 0x0000FF00) >> 8; + streamer.EmitIntValue(b, 1); + b = w & 0x000000FF; + streamer.EmitIntValue(b, 1); + break; + } + case Win64EH::UOP_SetFP: + b = 0xE1; + streamer.EmitIntValue(b, 1); + break; + case Win64EH::UOP_AddFP: + b = 0xE2; + streamer.EmitIntValue(b, 1); + b = (inst.Offset >> 3); + streamer.EmitIntValue(b, 1); + break; + case Win64EH::UOP_Nop: + b = 0xE3; + streamer.EmitIntValue(b, 1); + break; + case Win64EH::UOP_SaveFPLRX: + b = 0x80; + b |= ((inst.Offset - 1) >> 3) & 0x3F; + streamer.EmitIntValue(b, 1); + break; + case Win64EH::UOP_SaveFPLR: + b = 0x40; + b |= (inst.Offset >> 3) & 0x3F; + streamer.EmitIntValue(b, 1); + break; + case Win64EH::UOP_SaveReg: + assert(inst.Register >= 19 && "Saved reg must be >= 19"); + reg = inst.Register - 19; + b = 0xD0 | ((reg & 0xC) >> 2); + streamer.EmitIntValue(b, 1); + b = ((reg & 0x3) << 6) | (inst.Offset >> 3); + streamer.EmitIntValue(b, 1); + break; + case Win64EH::UOP_SaveRegX: + assert(inst.Register >= 19 && "Saved reg must be >= 19"); + reg = inst.Register - 19; + b = 0xD4 | ((reg & 0x8) >> 3); + streamer.EmitIntValue(b, 1); + b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1); + streamer.EmitIntValue(b, 1); + break; + case Win64EH::UOP_SaveRegP: + assert(inst.Register >= 19 && "Saved registers must be >= 19"); + reg = inst.Register - 19; + b = 0xC8 | ((reg & 0xC) >> 2); + streamer.EmitIntValue(b, 1); + b = ((reg & 0x3) << 6) | (inst.Offset >> 3); + streamer.EmitIntValue(b, 1); + break; + case Win64EH::UOP_SaveRegPX: + assert(inst.Register >= 19 && "Saved registers must be >= 19"); + reg = inst.Register - 19; + b = 0xCC | ((reg & 0xC) >> 2); + streamer.EmitIntValue(b, 1); + b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1); + streamer.EmitIntValue(b, 1); + break; + case Win64EH::UOP_SaveFReg: + assert(inst.Register >= 8 && "Saved dreg must be >= 8"); + reg = inst.Register - 8; + b = 0xDC | ((reg & 0x4) >> 2); + streamer.EmitIntValue(b, 1); + b = ((reg & 0x3) << 6) | (inst.Offset >> 3); + streamer.EmitIntValue(b, 1); + break; + case Win64EH::UOP_SaveFRegX: + assert(inst.Register >= 8 && "Saved dreg must be >= 8"); + reg = inst.Register - 8; + b = 0xDE; + streamer.EmitIntValue(b, 1); + b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1); + streamer.EmitIntValue(b, 1); + break; + case Win64EH::UOP_SaveFRegP: + assert(inst.Register >= 8 && "Saved dregs must be >= 8"); + reg = inst.Register - 8; + b = 0xD8 | ((reg & 0x4) >> 2); + streamer.EmitIntValue(b, 1); + b = ((reg & 0x3) << 6) | (inst.Offset >> 3); + streamer.EmitIntValue(b, 1); + break; + case Win64EH::UOP_SaveFRegPX: + assert(inst.Register >= 8 && "Saved dregs must be >= 8"); + reg = inst.Register - 8; + b = 0xDA | ((reg & 0x4) >> 2); + streamer.EmitIntValue(b, 1); + b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1); + streamer.EmitIntValue(b, 1); + break; + case Win64EH::UOP_End: + b = 0xE4; + streamer.EmitIntValue(b, 1); + break; + } +} + +// Populate the .xdata section. The format of .xdata on ARM64 is documented at +// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling +static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) { + // If this UNWIND_INFO already has a symbol, it's already been emitted. + if (info->Symbol) + return; + + MCContext &context = streamer.getContext(); + MCSymbol *Label = context.createTempSymbol(); + + streamer.EmitValueToAlignment(4); + streamer.EmitLabel(Label); + info->Symbol = Label; + + uint32_t FuncLength = 0x0; + if (info->FuncletOrFuncEnd) + FuncLength = (uint32_t)GetAbsDifference(streamer, info->FuncletOrFuncEnd, + info->Begin); + FuncLength /= 4; + uint32_t PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions); + uint32_t TotalCodeBytes = PrologCodeBytes; + + // Process epilogs. + MapVector<MCSymbol *, uint32_t> EpilogInfo; + for (auto &I : info->EpilogMap) { + MCSymbol *EpilogStart = I.first; + auto &EpilogInstrs = I.second; + uint32_t CodeBytes = ARM64CountOfUnwindCodes(EpilogInstrs); + EpilogInfo[EpilogStart] = TotalCodeBytes; + TotalCodeBytes += CodeBytes; + } + + // Code Words, Epilog count, E, X, Vers, Function Length + uint32_t row1 = 0x0; + uint32_t CodeWords = TotalCodeBytes / 4; + uint32_t CodeWordsMod = TotalCodeBytes % 4; + if (CodeWordsMod) + CodeWords++; + uint32_t EpilogCount = info->EpilogMap.size(); + bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124; + if (!ExtensionWord) { + row1 |= (EpilogCount & 0x1F) << 22; + row1 |= (CodeWords & 0x1F) << 27; + } + // E is always 0 right now, TODO: packed epilog setup + if (info->HandlesExceptions) // X + row1 |= 1 << 20; + row1 |= FuncLength & 0x3FFFF; + streamer.EmitIntValue(row1, 4); + + // Extended Code Words, Extended Epilog Count + if (ExtensionWord) { + // FIXME: We should be able to split unwind info into multiple sections. + // FIXME: We should share epilog codes across epilogs, where possible, + // which would make this issue show up less frequently. + if (CodeWords > 0xFF || EpilogCount > 0xFFFF) + report_fatal_error("SEH unwind data splitting not yet implemented"); + uint32_t row2 = 0x0; + row2 |= (CodeWords & 0xFF) << 16; + row2 |= (EpilogCount & 0xFFFF); + streamer.EmitIntValue(row2, 4); + } + + // Epilog Start Index, Epilog Start Offset + for (auto &I : EpilogInfo) { + MCSymbol *EpilogStart = I.first; + uint32_t EpilogIndex = I.second; + uint32_t EpilogOffset = + (uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin); + if (EpilogOffset) + EpilogOffset /= 4; + uint32_t row3 = EpilogOffset; + row3 |= (EpilogIndex & 0x3FF) << 22; + streamer.EmitIntValue(row3, 4); + } + + // Emit prolog unwind instructions (in reverse order). + uint8_t numInst = info->Instructions.size(); + for (uint8_t c = 0; c < numInst; ++c) { + WinEH::Instruction inst = info->Instructions.back(); + info->Instructions.pop_back(); + ARM64EmitUnwindCode(streamer, info->Begin, inst); + } + + // Emit epilog unwind instructions + for (auto &I : info->EpilogMap) { + auto &EpilogInstrs = I.second; + for (uint32_t i = 0; i < EpilogInstrs.size(); i++) { + WinEH::Instruction inst = EpilogInstrs[i]; + ARM64EmitUnwindCode(streamer, info->Begin, inst); + } + } + + int32_t BytesMod = CodeWords * 4 - TotalCodeBytes; + assert(BytesMod >= 0); + for (int i = 0; i < BytesMod; i++) + streamer.EmitIntValue(0xE3, 1); + + if (info->HandlesExceptions) + streamer.EmitValue( + MCSymbolRefExpr::create(info->ExceptionHandler, + MCSymbolRefExpr::VK_COFF_IMGREL32, context), + 4); +} + +static void ARM64EmitRuntimeFunction(MCStreamer &streamer, + const WinEH::FrameInfo *info) { + MCContext &context = streamer.getContext(); + + streamer.EmitValueToAlignment(4); + EmitSymbolRefWithOfs(streamer, info->Function, info->Begin); + streamer.EmitValue(MCSymbolRefExpr::create(info->Symbol, + MCSymbolRefExpr::VK_COFF_IMGREL32, + context), + 4); +} + +void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const { + // Emit the unwind info structs first. + for (const auto &CFI : Streamer.getWinFrameInfos()) { + MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection); + Streamer.SwitchSection(XData); + ARM64EmitUnwindInfo(Streamer, CFI.get()); + } + + // Now emit RUNTIME_FUNCTION entries. + for (const auto &CFI : Streamer.getWinFrameInfos()) { + MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection); + Streamer.SwitchSection(PData); + ARM64EmitRuntimeFunction(Streamer, CFI.get()); + } +} + +void llvm::Win64EH::ARM64UnwindEmitter::EmitUnwindInfo( + MCStreamer &Streamer, WinEH::FrameInfo *info) const { + // Switch sections (the static function above is meant to be called from + // here and from Emit(). + MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection); + Streamer.SwitchSection(XData); + ARM64EmitUnwindInfo(Streamer, info); +} diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp index 2664528909af..2fa65658ccfa 100644 --- a/lib/MC/MachObjectWriter.cpp +++ b/lib/MC/MachObjectWriter.cpp @@ -597,8 +597,8 @@ void MachObjectWriter::computeSymbolTable( } // External and undefined symbols are required to be in lexicographic order. - llvm::sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); - llvm::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); + llvm::sort(ExternalSymbolData); + llvm::sort(UndefinedSymbolData); // Set the symbol indices. Index = 0; @@ -846,18 +846,27 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, // Write out the deployment target information, if it's available. if (VersionInfo.Major != 0) { - assert(VersionInfo.Update < 256 && "unencodable update target version"); - assert(VersionInfo.Minor < 256 && "unencodable minor target version"); - assert(VersionInfo.Major < 65536 && "unencodable major target version"); - uint32_t EncodedVersion = VersionInfo.Update | (VersionInfo.Minor << 8) | - (VersionInfo.Major << 16); + auto EncodeVersion = [](VersionTuple V) -> uint32_t { + assert(!V.empty() && "empty version"); + unsigned Update = V.getSubminor() ? *V.getSubminor() : 0; + unsigned Minor = V.getMinor() ? *V.getMinor() : 0; + assert(Update < 256 && "unencodable update target version"); + assert(Minor < 256 && "unencodable minor target version"); + assert(V.getMajor() < 65536 && "unencodable major target version"); + return Update | (Minor << 8) | (V.getMajor() << 16); + }; + uint32_t EncodedVersion = EncodeVersion( + VersionTuple(VersionInfo.Major, VersionInfo.Minor, VersionInfo.Update)); + uint32_t SDKVersion = !VersionInfo.SDKVersion.empty() + ? EncodeVersion(VersionInfo.SDKVersion) + : 0; if (VersionInfo.EmitBuildVersion) { // FIXME: Currently empty tools. Add clang version in the future. W.write<uint32_t>(MachO::LC_BUILD_VERSION); W.write<uint32_t>(sizeof(MachO::build_version_command)); W.write<uint32_t>(VersionInfo.TypeOrPlatform.Platform); W.write<uint32_t>(EncodedVersion); - W.write<uint32_t>(0); // SDK version. + W.write<uint32_t>(SDKVersion); W.write<uint32_t>(0); // Empty tools list. } else { MachO::LoadCommandType LCType @@ -865,7 +874,7 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, W.write<uint32_t>(LCType); W.write<uint32_t>(sizeof(MachO::version_min_command)); W.write<uint32_t>(EncodedVersion); - W.write<uint32_t>(0); // reserved. + W.write<uint32_t>(SDKVersion); } } diff --git a/lib/MC/WasmObjectWriter.cpp b/lib/MC/WasmObjectWriter.cpp index 5a979d36e81b..0cca3757be90 100644 --- a/lib/MC/WasmObjectWriter.cpp +++ b/lib/MC/WasmObjectWriter.cpp @@ -56,9 +56,10 @@ struct SectionBookkeeping { uint32_t Index; }; -// The signature of a wasm function, in a struct capable of being used as a -// DenseMap key. -struct WasmFunctionType { +// The signature of a wasm function or event, in a struct capable of being used +// as a DenseMap key. +// TODO: Consider using wasm::WasmSignature directly instead. +struct WasmSignature { // Support empty and tombstone instances, needed by DenseMap. enum { Plain, Empty, Tombstone } State; @@ -68,36 +69,35 @@ struct WasmFunctionType { // The parameter types of the function. SmallVector<wasm::ValType, 4> Params; - WasmFunctionType() : State(Plain) {} + WasmSignature() : State(Plain) {} - bool operator==(const WasmFunctionType &Other) const { + bool operator==(const WasmSignature &Other) const { return State == Other.State && Returns == Other.Returns && Params == Other.Params; } }; -// Traits for using WasmFunctionType in a DenseMap. -struct WasmFunctionTypeDenseMapInfo { - static WasmFunctionType getEmptyKey() { - WasmFunctionType FuncTy; - FuncTy.State = WasmFunctionType::Empty; - return FuncTy; +// Traits for using WasmSignature in a DenseMap. +struct WasmSignatureDenseMapInfo { + static WasmSignature getEmptyKey() { + WasmSignature Sig; + Sig.State = WasmSignature::Empty; + return Sig; } - static WasmFunctionType getTombstoneKey() { - WasmFunctionType FuncTy; - FuncTy.State = WasmFunctionType::Tombstone; - return FuncTy; + static WasmSignature getTombstoneKey() { + WasmSignature Sig; + Sig.State = WasmSignature::Tombstone; + return Sig; } - static unsigned getHashValue(const WasmFunctionType &FuncTy) { - uintptr_t Value = FuncTy.State; - for (wasm::ValType Ret : FuncTy.Returns) - Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Ret)); - for (wasm::ValType Param : FuncTy.Params) - Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Param)); + static unsigned getHashValue(const WasmSignature &Sig) { + uintptr_t Value = Sig.State; + for (wasm::ValType Ret : Sig.Returns) + Value += DenseMapInfo<uint32_t>::getHashValue(uint32_t(Ret)); + for (wasm::ValType Param : Sig.Params) + Value += DenseMapInfo<uint32_t>::getHashValue(uint32_t(Param)); return Value; } - static bool isEqual(const WasmFunctionType &LHS, - const WasmFunctionType &RHS) { + static bool isEqual(const WasmSignature &LHS, const WasmSignature &RHS) { return LHS == RHS; } }; @@ -117,7 +117,7 @@ struct WasmDataSegment { // A wasm function to be written into the function section. struct WasmFunction { - int32_t Type; + uint32_t SigIndex; const MCSymbolWasm *Sym; }; @@ -137,11 +137,11 @@ struct WasmComdatEntry { // Information about a single relocation. struct WasmRelocationEntry { - uint64_t Offset; // Where is the relocation. - const MCSymbolWasm *Symbol; // The symbol to relocate with. - int64_t Addend; // A value to add to the symbol. - unsigned Type; // The type of the relocation. - const MCSectionWasm *FixupSection;// The section the relocation is targeting. + uint64_t Offset; // Where is the relocation. + const MCSymbolWasm *Symbol; // The symbol to relocate with. + int64_t Addend; // A value to add to the symbol. + unsigned Type; // The type of the relocation. + const MCSectionWasm *FixupSection; // The section the relocation is targeting. WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol, int64_t Addend, unsigned Type, @@ -163,8 +163,8 @@ struct WasmRelocationEntry { } void print(raw_ostream &Out) const { - Out << wasm::relocTypetoString(Type) - << " Off=" << Offset << ", Sym=" << *Symbol << ", Addend=" << Addend + Out << wasm::relocTypetoString(Type) << " Off=" << Offset + << ", Sym=" << *Symbol << ", Addend=" << Addend << ", FixupSection=" << FixupSection->getSectionName(); } @@ -215,7 +215,8 @@ class WasmObjectWriter : public MCObjectWriter { // Maps function symbols to the table element index space. Used // for TABLE_INDEX relocation types (i.e. address taken functions). DenseMap<const MCSymbolWasm *, uint32_t> TableIndices; - // Maps function/global symbols to the function/global/section index space. + // Maps function/global symbols to the function/global/event/section index + // space. DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices; // Maps data symbols to the Wasm segment and offset/size with the segment. DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations; @@ -230,13 +231,13 @@ class WasmObjectWriter : public MCObjectWriter { // Map from section to defining function symbol. DenseMap<const MCSection *, const MCSymbol *> SectionFunctions; - DenseMap<WasmFunctionType, int32_t, WasmFunctionTypeDenseMapInfo> - FunctionTypeIndices; - SmallVector<WasmFunctionType, 4> FunctionTypes; + DenseMap<WasmSignature, uint32_t, WasmSignatureDenseMapInfo> SignatureIndices; + SmallVector<WasmSignature, 4> Signatures; SmallVector<WasmGlobal, 4> Globals; SmallVector<WasmDataSegment, 4> DataSegments; unsigned NumFunctionImports = 0; unsigned NumGlobalImports = 0; + unsigned NumEventImports = 0; uint32_t SectionCount = 0; // TargetObjectWriter wrappers. @@ -265,8 +266,8 @@ private: TableIndices.clear(); DataLocations.clear(); CustomSectionsRelocations.clear(); - FunctionTypeIndices.clear(); - FunctionTypes.clear(); + SignatureIndices.clear(); + Signatures.clear(); Globals.clear(); DataSegments.clear(); SectionFunctions.clear(); @@ -291,11 +292,9 @@ private: W.OS << Str; } - void writeValueType(wasm::ValType Ty) { - W.OS << static_cast<char>(Ty); - } + void writeValueType(wasm::ValType Ty) { W.OS << static_cast<char>(Ty); } - void writeTypeSection(ArrayRef<WasmFunctionType> FunctionTypes); + void writeTypeSection(ArrayRef<WasmSignature> Signatures); void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize, uint32_t NumElements); void writeFunctionSection(ArrayRef<WasmFunction> Functions); @@ -305,8 +304,9 @@ private: void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, ArrayRef<WasmFunction> Functions); void writeDataSection(); + void writeEventSection(ArrayRef<wasm::WasmEventType> Events); void writeRelocSection(uint32_t SectionIndex, StringRef Name, - ArrayRef<WasmRelocationEntry> Relocations); + std::vector<WasmRelocationEntry> &Relocations); void writeLinkingMetaDataSection( ArrayRef<wasm::WasmSymbolInfo> SymbolInfos, ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs, @@ -323,7 +323,9 @@ private: uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry); uint32_t getFunctionType(const MCSymbolWasm &Symbol); - uint32_t registerFunctionType(const MCSymbolWasm &Symbol); + uint32_t getEventType(const MCSymbolWasm &Symbol); + void registerFunctionType(const MCSymbolWasm &Symbol); + void registerEventType(const MCSymbolWasm &Symbol); }; } // end anonymous namespace @@ -529,8 +531,8 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, // Write X as an (unsigned) LEB value at offset Offset in Stream, padded // to allow patching. -static void -WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { +static void WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, + uint64_t Offset) { uint8_t Buffer[5]; unsigned SizeLen = encodeULEB128(X, Buffer, 5); assert(SizeLen == 5); @@ -539,8 +541,8 @@ WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { // Write X as an signed LEB value at offset Offset in Stream, padded // to allow patching. -static void -WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, uint64_t Offset) { +static void WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, + uint64_t Offset) { uint8_t Buffer[5]; unsigned SizeLen = encodeSLEB128(X, Buffer, 5); assert(SizeLen == 5); @@ -554,7 +556,7 @@ static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset); } -static const MCSymbolWasm* ResolveSymbol(const MCSymbolWasm& Symbol) { +static const MCSymbolWasm *ResolveSymbol(const MCSymbolWasm &Symbol) { if (Symbol.isVariable()) { const MCExpr *Expr = Symbol.getVariableValue(); auto *Inner = cast<MCSymbolRefExpr>(Expr); @@ -582,7 +584,8 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { return getRelocationIndexValue(RelEntry); case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - // Provisional value is function/global Wasm index + case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB: + // Provisional value is function/global/event Wasm index if (!WasmIndices.count(RelEntry.Symbol)) report_fatal_error("symbol not found in wasm index space: " + RelEntry.Symbol->getName()); @@ -626,10 +629,9 @@ static void addData(SmallVectorImpl<char> &DataBytes, report_fatal_error("only byte values supported for alignment"); // If nops are requested, use zeros, as this is the data section. uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue(); - uint64_t Size = std::min<uint64_t>(alignTo(DataBytes.size(), - Align->getAlignment()), - DataBytes.size() + - Align->getMaxBytesToEmit()); + uint64_t Size = + std::min<uint64_t>(alignTo(DataBytes.size(), Align->getAlignment()), + DataBytes.size() + Align->getMaxBytesToEmit()); DataBytes.resize(Size, Value); } else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) { int64_t NumValues; @@ -637,10 +639,12 @@ static void addData(SmallVectorImpl<char> &DataBytes, llvm_unreachable("The fill should be an assembler constant"); DataBytes.insert(DataBytes.end(), Fill->getValueSize() * NumValues, Fill->getValue()); + } else if (auto *LEB = dyn_cast<MCLEBFragment>(&Frag)) { + const SmallVectorImpl<char> &Contents = LEB->getContents(); + DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); } else { const auto &DataFrag = cast<MCDataFragment>(Frag); const SmallVectorImpl<char> &Contents = DataFrag.getContents(); - DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); } } @@ -678,6 +682,7 @@ void WasmObjectWriter::applyRelocations( case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB: WritePatchableLEB(Stream, Value, Offset); break; case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: @@ -696,23 +701,22 @@ void WasmObjectWriter::applyRelocations( } } -void WasmObjectWriter::writeTypeSection( - ArrayRef<WasmFunctionType> FunctionTypes) { - if (FunctionTypes.empty()) +void WasmObjectWriter::writeTypeSection(ArrayRef<WasmSignature> Signatures) { + if (Signatures.empty()) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_TYPE); - encodeULEB128(FunctionTypes.size(), W.OS); + encodeULEB128(Signatures.size(), W.OS); - for (const WasmFunctionType &FuncTy : FunctionTypes) { + for (const WasmSignature &Sig : Signatures) { W.OS << char(wasm::WASM_TYPE_FUNC); - encodeULEB128(FuncTy.Params.size(), W.OS); - for (wasm::ValType Ty : FuncTy.Params) + encodeULEB128(Sig.Params.size(), W.OS); + for (wasm::ValType Ty : Sig.Params) writeValueType(Ty); - encodeULEB128(FuncTy.Returns.size(), W.OS); - for (wasm::ValType Ty : FuncTy.Returns) + encodeULEB128(Sig.Returns.size(), W.OS); + for (wasm::ValType Ty : Sig.Returns) writeValueType(Ty); } @@ -745,14 +749,18 @@ void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports, W.OS << char(Import.Global.Mutable ? 1 : 0); break; case wasm::WASM_EXTERNAL_MEMORY: - encodeULEB128(0, W.OS); // flags + encodeULEB128(0, W.OS); // flags encodeULEB128(NumPages, W.OS); // initial break; case wasm::WASM_EXTERNAL_TABLE: W.OS << char(Import.Table.ElemType); - encodeULEB128(0, W.OS); // flags + encodeULEB128(0, W.OS); // flags encodeULEB128(NumElements, W.OS); // initial break; + case wasm::WASM_EXTERNAL_EVENT: + encodeULEB128(Import.Event.Attribute, W.OS); + encodeULEB128(Import.Event.SigIndex, W.OS); + break; default: llvm_unreachable("unsupported import kind"); } @@ -770,7 +778,7 @@ void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) { encodeULEB128(Functions.size(), W.OS); for (const WasmFunction &Func : Functions) - encodeULEB128(Func.Type, W.OS); + encodeULEB128(Func.SigIndex, W.OS); endSection(Section); } @@ -795,6 +803,22 @@ void WasmObjectWriter::writeGlobalSection() { endSection(Section); } +void WasmObjectWriter::writeEventSection(ArrayRef<wasm::WasmEventType> Events) { + if (Events.empty()) + return; + + SectionBookkeeping Section; + startSection(Section, wasm::WASM_SEC_EVENT); + + encodeULEB128(Events.size(), W.OS); + for (const wasm::WasmEventType &Event : Events) { + encodeULEB128(Event.Attribute, W.OS); + encodeULEB128(Event.SigIndex, W.OS); + } + + endSection(Section); +} + void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) { if (Exports.empty()) return; @@ -892,21 +916,33 @@ void WasmObjectWriter::writeDataSection() { void WasmObjectWriter::writeRelocSection( uint32_t SectionIndex, StringRef Name, - ArrayRef<WasmRelocationEntry> Relocations) { + std::vector<WasmRelocationEntry> &Relocs) { // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md // for descriptions of the reloc sections. - if (Relocations.empty()) + if (Relocs.empty()) return; + // First, ensure the relocations are sorted in offset order. In general they + // should already be sorted since `recordRelocation` is called in offset + // order, but for the code section we combine many MC sections into single + // wasm section, and this order is determined by the order of Asm.Symbols() + // not the sections order. + std::stable_sort( + Relocs.begin(), Relocs.end(), + [](const WasmRelocationEntry &A, const WasmRelocationEntry &B) { + return (A.Offset + A.FixupSection->getSectionOffset()) < + (B.Offset + B.FixupSection->getSectionOffset()); + }); + SectionBookkeeping Section; startCustomSection(Section, std::string("reloc.") + Name.str()); encodeULEB128(SectionIndex, W.OS); - encodeULEB128(Relocations.size(), W.OS); - for (const WasmRelocationEntry& RelEntry : Relocations) { - uint64_t Offset = RelEntry.Offset + - RelEntry.FixupSection->getSectionOffset(); + encodeULEB128(Relocs.size(), W.OS); + for (const WasmRelocationEntry &RelEntry : Relocs) { + uint64_t Offset = + RelEntry.Offset + RelEntry.FixupSection->getSectionOffset(); uint32_t Index = getRelocationIndexValue(RelEntry); W.OS << char(RelEntry.Type); @@ -944,6 +980,7 @@ void WasmObjectWriter::writeLinkingMetaDataSection( switch (Sym.Kind) { case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_GLOBAL: + case wasm::WASM_SYMBOL_TYPE_EVENT: encodeULEB128(Sym.ElementIndex, W.OS); if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) writeString(Sym.Name); @@ -984,7 +1021,7 @@ void WasmObjectWriter::writeLinkingMetaDataSection( startSection(SubSection, wasm::WASM_INIT_FUNCS); encodeULEB128(InitFuncs.size(), W.OS); for (auto &StartFunc : InitFuncs) { - encodeULEB128(StartFunc.first, W.OS); // priority + encodeULEB128(StartFunc.first, W.OS); // priority encodeULEB128(StartFunc.second, W.OS); // function index } endSection(SubSection); @@ -1029,30 +1066,57 @@ void WasmObjectWriter::writeCustomSections(const MCAssembler &Asm, } } -uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm& Symbol) { +uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm &Symbol) { assert(Symbol.isFunction()); assert(TypeIndices.count(&Symbol)); return TypeIndices[&Symbol]; } -uint32_t WasmObjectWriter::registerFunctionType(const MCSymbolWasm& Symbol) { +uint32_t WasmObjectWriter::getEventType(const MCSymbolWasm &Symbol) { + assert(Symbol.isEvent()); + assert(TypeIndices.count(&Symbol)); + return TypeIndices[&Symbol]; +} + +void WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) { assert(Symbol.isFunction()); - WasmFunctionType F; - const MCSymbolWasm* ResolvedSym = ResolveSymbol(Symbol); - F.Returns = ResolvedSym->getReturns(); - F.Params = ResolvedSym->getParams(); + WasmSignature S; + const MCSymbolWasm *ResolvedSym = ResolveSymbol(Symbol); + if (auto *Sig = ResolvedSym->getSignature()) { + S.Returns = Sig->Returns; + S.Params = Sig->Params; + } - auto Pair = - FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size())); + auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size())); if (Pair.second) - FunctionTypes.push_back(F); + Signatures.push_back(S); TypeIndices[&Symbol] = Pair.first->second; LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol << " new:" << Pair.second << "\n"); LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n"); - return Pair.first->second; +} + +void WasmObjectWriter::registerEventType(const MCSymbolWasm &Symbol) { + assert(Symbol.isEvent()); + + // TODO Currently we don't generate imported exceptions, but if we do, we + // should have a way of infering types of imported exceptions. + WasmSignature S; + if (auto *Sig = Symbol.getSignature()) { + S.Returns = Sig->Returns; + S.Params = Sig->Params; + } + + auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size())); + if (Pair.second) + Signatures.push_back(S); + TypeIndices[&Symbol] = Pair.first->second; + + LLVM_DEBUG(dbgs() << "registerEventType: " << Symbol << " new:" << Pair.second + << "\n"); + LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n"); } static bool isInSymtab(const MCSymbolWasm &Sym) { @@ -1086,6 +1150,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, SmallVector<uint32_t, 4> TableElems; SmallVector<wasm::WasmImport, 4> Imports; SmallVector<wasm::WasmExport, 4> Exports; + SmallVector<wasm::WasmEventType, 1> Events; SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos; SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs; std::map<StringRef, std::vector<WasmComdatEntry>> Comdats; @@ -1111,10 +1176,10 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, TableImport.Module = TableSym->getModuleName(); TableImport.Field = TableSym->getName(); TableImport.Kind = wasm::WASM_EXTERNAL_TABLE; - TableImport.Table.ElemType = wasm::WASM_TYPE_ANYFUNC; + TableImport.Table.ElemType = wasm::WASM_TYPE_FUNCREF; Imports.push_back(TableImport); - // Populate FunctionTypeIndices, and Imports and WasmIndices for undefined + // Populate SignatureIndices, and Imports and WasmIndices for undefined // symbols. This must be done before populating WasmIndices for defined // symbols. for (const MCSymbol &S : Asm.symbols()) { @@ -1125,6 +1190,9 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, if (WS.isFunction()) registerFunctionType(WS); + if (WS.isEvent()) + registerEventType(WS); + if (WS.isTemporary()) continue; @@ -1149,6 +1217,18 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, Import.Global = WS.getGlobalType(); Imports.push_back(Import); WasmIndices[&WS] = NumGlobalImports++; + } else if (WS.isEvent()) { + if (WS.isWeak()) + report_fatal_error("undefined event symbol cannot be weak"); + + wasm::WasmImport Import; + Import.Module = WS.getModuleName(); + Import.Field = WS.getName(); + Import.Kind = wasm::WASM_EXTERNAL_EVENT; + Import.Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION; + Import.Event.SigIndex = getEventType(WS); + Imports.push_back(Import); + WasmIndices[&WS] = NumEventImports++; } } } @@ -1176,7 +1256,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, Segment.Offset = DataSize; Segment.Section = &Section; addData(Segment.Data, Section); - Segment.Alignment = Section.getAlignment(); + Segment.Alignment = Log2_32(Section.getAlignment()); Segment.Flags = 0; DataSize += Segment.Data.size(); Section.setSegmentIndex(SegmentIndex); @@ -1195,7 +1275,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, if (Name.startswith(".custom_section.")) Name = Name.substr(strlen(".custom_section.")); - MCSymbol* Begin = Sec.getBeginSymbol(); + MCSymbol *Begin = Sec.getBeginSymbol(); if (Begin) { WasmIndices[cast<MCSymbolWasm>(Begin)] = CustomSections.size(); if (SectionName != Begin->getName()) @@ -1240,7 +1320,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // A definition. Write out the function body. Index = NumFunctionImports + Functions.size(); WasmFunction Func; - Func.Type = getFunctionType(WS); + Func.SigIndex = getFunctionType(WS); Func.Sym = &WS; WasmIndices[&WS] = Index; Functions.push_back(Func); @@ -1256,6 +1336,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, } LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n"); + } else if (WS.isData()) { if (WS.isTemporary() && !WS.getSize()) continue; @@ -1285,6 +1366,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, static_cast<uint32_t>(Size)}; DataLocations[&WS] = Ref; LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n"); + } else if (WS.isGlobal()) { // A "true" Wasm global (currently just __stack_pointer) if (WS.isDefined()) @@ -1293,6 +1375,24 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // An import; the index was assigned above LLVM_DEBUG(dbgs() << " -> global index: " << WasmIndices.find(&WS)->second << "\n"); + + } else if (WS.isEvent()) { + // C++ exception symbol (__cpp_exception) + unsigned Index; + if (WS.isDefined()) { + Index = NumEventImports + Events.size(); + wasm::WasmEventType Event; + Event.SigIndex = getEventType(WS); + Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION; + WasmIndices[&WS] = Index; + Events.push_back(Event); + } else { + // An import; the index was assigned above. + Index = WasmIndices.find(&WS)->second; + } + LLVM_DEBUG(dbgs() << " -> event index: " << WasmIndices.find(&WS)->second + << "\n"); + } else { assert(WS.isSection()); } @@ -1326,7 +1426,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, DataLocations[&WS] = Ref; LLVM_DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n"); } else { - report_fatal_error("don't yet support global aliases"); + report_fatal_error("don't yet support global/event aliases"); } } @@ -1424,7 +1524,8 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, unsigned PrefixLength = strlen(".init_array"); if (WS.getSectionName().size() > PrefixLength) { if (WS.getSectionName()[PrefixLength] != '.') - report_fatal_error(".init_array section priority should start with '.'"); + report_fatal_error( + ".init_array section priority should start with '.'"); if (WS.getSectionName() .substr(PrefixLength + 1) .getAsInteger(10, Priority)) @@ -1432,14 +1533,16 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, } const auto &DataFrag = cast<MCDataFragment>(Frag); const SmallVectorImpl<char> &Contents = DataFrag.getContents(); - for (const uint8_t *p = (const uint8_t *)Contents.data(), - *end = (const uint8_t *)Contents.data() + Contents.size(); + for (const uint8_t * + p = (const uint8_t *)Contents.data(), + *end = (const uint8_t *)Contents.data() + Contents.size(); p != end; ++p) { if (*p != 0) report_fatal_error("non-symbolic data in .init_array section"); } for (const MCFixup &Fixup : DataFrag.getFixups()) { - assert(Fixup.getKind() == MCFixup::getKindForSize(is64Bit() ? 8 : 4, false)); + assert(Fixup.getKind() == + MCFixup::getKindForSize(is64Bit() ? 8 : 4, false)); const MCExpr *Expr = Fixup.getValue(); auto *Sym = dyn_cast<MCSymbolRefExpr>(Expr); if (!Sym) @@ -1456,12 +1559,13 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // Write out the Wasm header. writeHeader(Asm); - writeTypeSection(FunctionTypes); + writeTypeSection(Signatures); writeImportSection(Imports, DataSize, TableElems.size()); writeFunctionSection(Functions); // Skip the "table" section; we import the table instead. // Skip the "memory" section; we import the memory instead. writeGlobalSection(); + writeEventSection(Events); writeExportSection(Exports); writeElemSection(TableElems); writeCodeSection(Asm, Layout, Functions); diff --git a/lib/MC/WinCOFFObjectWriter.cpp b/lib/MC/WinCOFFObjectWriter.cpp index 9ffecd99df68..b774852eabe6 100644 --- a/lib/MC/WinCOFFObjectWriter.cpp +++ b/lib/MC/WinCOFFObjectWriter.cpp @@ -36,6 +36,7 @@ #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" #include <algorithm> @@ -58,8 +59,6 @@ namespace { using name = SmallString<COFF::NameSize>; enum AuxiliaryType { - ATFunctionDefinition, - ATbfAndefSymbol, ATWeakExternal, ATFile, ATSectionDefinition @@ -147,6 +146,10 @@ public: bool UseBigObj; + bool EmitAddrsigSection = false; + MCSectionCOFF *AddrsigSection; + std::vector<const MCSymbol *> AddrsigSyms; + WinCOFFObjectWriter(std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS); @@ -206,6 +209,11 @@ public: void assignSectionNumbers(); void assignFileOffsets(MCAssembler &Asm, const MCAsmLayout &Layout); + void emitAddrsigSection() override { EmitAddrsigSection = true; } + void addAddrsigSymbol(const MCSymbol *Sym) override { + AddrsigSyms.push_back(Sym); + } + uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; }; @@ -515,24 +523,6 @@ void WinCOFFObjectWriter::WriteAuxiliarySymbols( const COFFSymbol::AuxiliarySymbols &S) { for (const AuxSymbol &i : S) { switch (i.AuxType) { - case ATFunctionDefinition: - W.write<uint32_t>(i.Aux.FunctionDefinition.TagIndex); - W.write<uint32_t>(i.Aux.FunctionDefinition.TotalSize); - W.write<uint32_t>(i.Aux.FunctionDefinition.PointerToLinenumber); - W.write<uint32_t>(i.Aux.FunctionDefinition.PointerToNextFunction); - W.OS.write_zeros(sizeof(i.Aux.FunctionDefinition.unused)); - if (UseBigObj) - W.OS.write_zeros(COFF::Symbol32Size - COFF::Symbol16Size); - break; - case ATbfAndefSymbol: - W.OS.write_zeros(sizeof(i.Aux.bfAndefSymbol.unused1)); - W.write<uint16_t>(i.Aux.bfAndefSymbol.Linenumber); - W.OS.write_zeros(sizeof(i.Aux.bfAndefSymbol.unused2)); - W.write<uint32_t>(i.Aux.bfAndefSymbol.PointerToNextFunction); - W.OS.write_zeros(sizeof(i.Aux.bfAndefSymbol.unused3)); - if (UseBigObj) - W.OS.write_zeros(COFF::Symbol32Size - COFF::Symbol16Size); - break; case ATWeakExternal: W.write<uint32_t>(i.Aux.WeakExternal.TagIndex); W.write<uint32_t>(i.Aux.WeakExternal.Characteristics); @@ -568,10 +558,9 @@ void WinCOFFObjectWriter::writeSectionHeaders() { std::vector<COFFSection *> Arr; for (auto &Section : Sections) Arr.push_back(Section.get()); - llvm::sort(Arr.begin(), Arr.end(), - [](const COFFSection *A, const COFFSection *B) { - return A->Number < B->Number; - }); + llvm::sort(Arr, [](const COFFSection *A, const COFFSection *B) { + return A->Number < B->Number; + }); for (auto &Section : Arr) { if (Section->Number == -1) @@ -630,14 +619,9 @@ void WinCOFFObjectWriter::writeSection(MCAssembler &Asm, // Write the section contents. if (Sec.Header.PointerToRawData != 0) { - assert(W.OS.tell() <= Sec.Header.PointerToRawData && + assert(W.OS.tell() == Sec.Header.PointerToRawData && "Section::PointerToRawData is insane!"); - unsigned PaddingSize = Sec.Header.PointerToRawData - W.OS.tell(); - assert(PaddingSize < 4 && - "Should only need at most three bytes of padding!"); - W.OS.write_zeros(PaddingSize); - uint32_t CRC = writeSectionContents(Asm, Layout, MCSec); // Update the section definition auxiliary symbol to record the CRC. @@ -677,6 +661,13 @@ void WinCOFFObjectWriter::writeSection(MCAssembler &Asm, void WinCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { + if (EmitAddrsigSection) { + AddrsigSection = Asm.getContext().getCOFFSection( + ".llvm_addrsig", COFF::IMAGE_SCN_LNK_REMOVE, + SectionKind::getMetadata()); + Asm.registerSection(*AddrsigSection); + } + // "Define" each section & symbol. This creates section & symbol // entries in the staging area. for (const auto &Section : Asm) @@ -915,10 +906,7 @@ void WinCOFFObjectWriter::assignFileOffsets(MCAssembler &Asm, Sec->Header.SizeOfRawData = Layout.getSectionAddressSize(&Section); if (IsPhysicalSection(Sec)) { - // Align the section data to a four byte boundary. - Offset = alignTo(Offset, 4); Sec->Header.PointerToRawData = Offset; - Offset += Sec->Header.SizeOfRawData; } @@ -1020,22 +1008,47 @@ uint64_t WinCOFFObjectWriter::writeObject(MCAssembler &Asm, continue; const MCSectionCOFF &MCSec = *Section->MCSection; + const MCSymbol *AssocMCSym = MCSec.getCOMDATSymbol(); + assert(AssocMCSym); + + // It's an error to try to associate with an undefined symbol or a symbol + // without a section. + if (!AssocMCSym->isInSection()) { + Asm.getContext().reportError( + SMLoc(), Twine("cannot make section ") + MCSec.getSectionName() + + Twine(" associative with sectionless symbol ") + + AssocMCSym->getName()); + continue; + } - const MCSymbol *COMDAT = MCSec.getCOMDATSymbol(); - assert(COMDAT); - COFFSymbol *COMDATSymbol = GetOrCreateCOFFSymbol(COMDAT); - assert(COMDATSymbol); - COFFSection *Assoc = COMDATSymbol->Section; - if (!Assoc) - report_fatal_error( - Twine("Missing associated COMDAT section for section ") + - MCSec.getSectionName()); + const auto *AssocMCSec = cast<MCSectionCOFF>(&AssocMCSym->getSection()); + assert(SectionMap.count(AssocMCSec)); + COFFSection *AssocSec = SectionMap[AssocMCSec]; // Skip this section if the associated section is unused. - if (Assoc->Number == -1) + if (AssocSec->Number == -1) continue; - Section->Symbol->Aux[0].Aux.SectionDefinition.Number = Assoc->Number; + Section->Symbol->Aux[0].Aux.SectionDefinition.Number = AssocSec->Number; + } + + // Create the contents of the .llvm_addrsig section. + if (EmitAddrsigSection) { + auto Frag = new MCDataFragment(AddrsigSection); + Frag->setLayoutOrder(0); + raw_svector_ostream OS(Frag->getContents()); + for (const MCSymbol *S : AddrsigSyms) { + if (!S->isTemporary()) { + encodeULEB128(S->getIndex(), OS); + continue; + } + + MCSection *TargetSection = &S->getSection(); + assert(SectionMap.find(TargetSection) != SectionMap.end() && + "Section must already have been defined in " + "executePostLayoutBinding!"); + encodeULEB128(SectionMap[TargetSection]->Symbol->getIndex(), OS); + } } assignFileOffsets(Asm, Layout); |