diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
commit | 044eb2f6afba375a914ac9d8024f8f5142bb912e (patch) | |
tree | 1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /lib/MC | |
parent | eb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff) |
Notes
Diffstat (limited to 'lib/MC')
38 files changed, 2207 insertions, 985 deletions
diff --git a/lib/MC/CMakeLists.txt b/lib/MC/CMakeLists.txt index 562f136a3ce2..b9e23d106e25 100644 --- a/lib/MC/CMakeLists.txt +++ b/lib/MC/CMakeLists.txt @@ -10,6 +10,7 @@ add_llvm_library(LLVMMC MCAsmStreamer.cpp MCAssembler.cpp MCCodeEmitter.cpp + MCCodePadder.cpp MCCodeView.cpp MCContext.cpp MCDwarf.cpp diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index c8dd63011943..e11eaaa30603 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -162,9 +162,10 @@ class ELFObjectWriter : public MCObjectWriter { bool ZLibStyle, unsigned Alignment); public: - ELFObjectWriter(MCELFObjectTargetWriter *MOTW, raw_pwrite_stream &OS, - bool IsLittleEndian) - : MCObjectWriter(OS, IsLittleEndian), TargetObjectWriter(MOTW) {} + ELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW, + raw_pwrite_stream &OS, bool IsLittleEndian) + : MCObjectWriter(OS, IsLittleEndian), + TargetObjectWriter(std::move(MOTW)) {} ~ELFObjectWriter() override = default; @@ -1108,7 +1109,7 @@ void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, if (is64Bit()) { write(Entry.Offset); - if (TargetObjectWriter->isN64()) { + if (TargetObjectWriter->getEMachine() == ELF::EM_MIPS) { write(uint32_t(Index)); write(TargetObjectWriter->getRSsym(Entry.Type)); @@ -1131,6 +1132,23 @@ void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, if (hasRelocationAddend()) write(uint32_t(Entry.Addend)); + + if (TargetObjectWriter->getEMachine() == ELF::EM_MIPS) { + if (uint32_t RType = TargetObjectWriter->getRType2(Entry.Type)) { + write(uint32_t(Entry.Offset)); + + ERE32.setSymbolAndType(0, RType); + write(ERE32.r_info); + write(uint32_t(0)); + } + if (uint32_t RType = TargetObjectWriter->getRType3(Entry.Type)) { + write(uint32_t(Entry.Offset)); + + ERE32.setSymbolAndType(0, RType); + write(ERE32.r_info); + write(uint32_t(0)); + } + } } } } @@ -1369,8 +1387,9 @@ bool ELFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl( InSet, IsPCRel); } -MCObjectWriter *llvm::createELFObjectWriter(MCELFObjectTargetWriter *MOTW, - raw_pwrite_stream &OS, - bool IsLittleEndian) { - return new ELFObjectWriter(MOTW, OS, IsLittleEndian); +std::unique_ptr<MCObjectWriter> +llvm::createELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW, + raw_pwrite_stream &OS, bool IsLittleEndian) { + return llvm::make_unique<ELFObjectWriter>(std::move(MOTW), OS, + IsLittleEndian); } diff --git a/lib/MC/MCAsmBackend.cpp b/lib/MC/MCAsmBackend.cpp index 3642f37aa855..b4a4d0a89966 100644 --- a/lib/MC/MCAsmBackend.cpp +++ b/lib/MC/MCAsmBackend.cpp @@ -10,6 +10,7 @@ #include "llvm/MC/MCAsmBackend.h" #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCCodePadder.h" #include "llvm/MC/MCFixupKindInfo.h" #include <cassert> #include <cstddef> @@ -17,7 +18,10 @@ using namespace llvm; -MCAsmBackend::MCAsmBackend() = default; +MCAsmBackend::MCAsmBackend() : CodePadder(new MCCodePadder()) {} + +MCAsmBackend::MCAsmBackend(std::unique_ptr<MCCodePadder> TargetCodePadder) + : CodePadder(std::move(TargetCodePadder)) {} MCAsmBackend::~MCAsmBackend() = default; @@ -59,3 +63,25 @@ bool MCAsmBackend::fixupNeedsRelaxationAdvanced( return true; return fixupNeedsRelaxation(Fixup, Value, DF, Layout); } + +void MCAsmBackend::handleCodePaddingBasicBlockStart( + MCObjectStreamer *OS, const MCCodePaddingContext &Context) { + CodePadder->handleBasicBlockStart(OS, Context); +} + +void MCAsmBackend::handleCodePaddingBasicBlockEnd( + const MCCodePaddingContext &Context) { + CodePadder->handleBasicBlockEnd(Context); +} + +void MCAsmBackend::handleCodePaddingInstructionBegin(const MCInst &Inst) { + CodePadder->handleInstructionBegin(Inst); +} + +void MCAsmBackend::handleCodePaddingInstructionEnd(const MCInst &Inst) { + CodePadder->handleInstructionEnd(Inst); +} + +bool MCAsmBackend::relaxFragment(MCPaddingFragment *PF, MCAsmLayout &Layout) { + return CodePadder->relaxFragment(PF, Layout); +}
\ No newline at end of file diff --git a/lib/MC/MCAsmInfoWasm.cpp b/lib/MC/MCAsmInfoWasm.cpp index aa26616dda36..fc55059ff75d 100644 --- a/lib/MC/MCAsmInfoWasm.cpp +++ b/lib/MC/MCAsmInfoWasm.cpp @@ -13,8 +13,6 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCAsmInfoWasm.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCSectionWasm.h" using namespace llvm; void MCAsmInfoWasm::anchor() { } diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 9e5553fa8d42..3357553cf19f 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -22,17 +22,14 @@ #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSymbolELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" -#include "llvm/Support/SourceMgr.h" #include <cctype> using namespace llvm; @@ -140,6 +137,8 @@ public: 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 EmitThumbFunc(MCSymbol *Func) override; void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; @@ -225,7 +224,9 @@ public: StringRef FileName) override; MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override; - bool EmitCVFileDirective(unsigned FileNo, StringRef Filename) override; + bool EmitCVFileDirective(unsigned FileNo, StringRef Filename, + ArrayRef<uint8_t> Checksum, + unsigned ChecksumKind) override; bool EmitCVFuncIdDirective(unsigned FuncId) override; bool EmitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc, unsigned IAFile, unsigned IALine, @@ -245,6 +246,8 @@ public: StringRef FixedSizePortion) override; void EmitCVStringTableDirective() override; void EmitCVFileChecksumsDirective() override; + void EmitCVFileChecksumOffsetDirective(unsigned FileNo) override; + void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc L) override; void EmitIdent(StringRef IdentString) override; void EmitCFISections(bool EH, bool Debug) override; @@ -256,6 +259,7 @@ public: void EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) override; void EmitCFIRememberState() override; void EmitCFIRestoreState() override; + void EmitCFIRestore(int64_t Register) override; void EmitCFISameValue(int64_t Register) override; void EmitCFIRelOffset(int64_t Register, int64_t Offset) override; void EmitCFIAdjustCfaOffset(int64_t Adjustment) override; @@ -265,21 +269,26 @@ public: void EmitCFIUndefined(int64_t Register) override; void EmitCFIRegister(int64_t Register1, int64_t Register2) override; void EmitCFIWindowSave() override; + void EmitCFIReturnColumn(int64_t Register) override; + + void EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) override; + void EmitWinCFIEndProc(SMLoc Loc) override; + void EmitWinCFIStartChained(SMLoc Loc) override; + void EmitWinCFIEndChained(SMLoc Loc) override; + void EmitWinCFIPushReg(unsigned Register, SMLoc Loc) override; + void EmitWinCFISetFrame(unsigned Register, unsigned Offset, + SMLoc Loc) override; + void EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) override; + void EmitWinCFISaveReg(unsigned Register, unsigned Offset, + SMLoc Loc) override; + void EmitWinCFISaveXMM(unsigned Register, unsigned Offset, + SMLoc Loc) override; + void EmitWinCFIPushFrame(bool Code, SMLoc Loc) override; + void EmitWinCFIEndProlog(SMLoc Loc) override; - void EmitWinCFIStartProc(const MCSymbol *Symbol) override; - void EmitWinCFIEndProc() override; - void EmitWinCFIStartChained() override; - void EmitWinCFIEndChained() override; - void EmitWinCFIPushReg(unsigned Register) override; - void EmitWinCFISetFrame(unsigned Register, unsigned Offset) override; - void EmitWinCFIAllocStack(unsigned Size) override; - void EmitWinCFISaveReg(unsigned Register, unsigned Offset) override; - void EmitWinCFISaveXMM(unsigned Register, unsigned Offset) override; - void EmitWinCFIPushFrame(bool Code) override; - void EmitWinCFIEndProlog() override; - - void EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except) override; - void EmitWinEHHandlerData() override; + void EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except, + SMLoc Loc) override; + void EmitWinEHHandlerData(SMLoc Loc) override; void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, bool PrintSchedInfo) override; @@ -464,15 +473,39 @@ void MCAsmStreamer::EmitDataRegion(MCDataRegionType Kind) { EmitEOL(); } -void MCAsmStreamer::EmitVersionMin(MCVersionMinType Kind, unsigned Major, +static const char *getVersionMinDirective(MCVersionMinType Type) { + switch (Type) { + case MCVM_WatchOSVersionMin: return ".watchos_version_min"; + case MCVM_TvOSVersionMin: return ".tvos_version_min"; + case MCVM_IOSVersionMin: return ".ios_version_min"; + case MCVM_OSXVersionMin: return ".macosx_version_min"; + } + llvm_unreachable("Invalid MC version min type"); +} + +void MCAsmStreamer::EmitVersionMin(MCVersionMinType Type, unsigned Major, unsigned Minor, unsigned Update) { - switch (Kind) { - case MCVM_WatchOSVersionMin: OS << "\t.watchos_version_min"; break; - case MCVM_TvOSVersionMin: OS << "\t.tvos_version_min"; break; - case MCVM_IOSVersionMin: OS << "\t.ios_version_min"; break; - case MCVM_OSXVersionMin: OS << "\t.macosx_version_min"; break; + OS << '\t' << getVersionMinDirective(Type) << ' ' << Major << ", " << Minor; + if (Update) + OS << ", " << Update; + 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"; } - OS << " " << Major << ", " << Minor; + llvm_unreachable("Invalid Mach-O platform type"); +} + +void MCAsmStreamer::EmitBuildVersion(unsigned Platform, unsigned Major, + unsigned Minor, unsigned Update) { + const char *PlatformName = getPlatformName((MachO::PlatformType)Platform); + OS << "\t.build_version " << PlatformName << ", " << Major << ", " << Minor; if (Update) OS << ", " << Update; EmitEOL(); @@ -1119,13 +1152,25 @@ MCSymbol *MCAsmStreamer::getDwarfLineTableSymbol(unsigned CUID) { return MCStreamer::getDwarfLineTableSymbol(0); } -bool MCAsmStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename) { - if (!getContext().getCVContext().addFile(FileNo, Filename)) +bool MCAsmStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename, + ArrayRef<uint8_t> Checksum, + unsigned ChecksumKind) { + if (!getContext().getCVContext().addFile(*this, FileNo, Filename, Checksum, + ChecksumKind)) return false; OS << "\t.cv_file\t" << FileNo << ' '; - PrintQuotedString(Filename, OS); + + if (!ChecksumKind) { + EmitEOL(); + return true; + } + + OS << ' '; + PrintQuotedString(toHex(Checksum), OS); + OS << ' ' << ChecksumKind; + EmitEOL(); return true; } @@ -1227,6 +1272,17 @@ void MCAsmStreamer::EmitCVFileChecksumsDirective() { EmitEOL(); } +void MCAsmStreamer::EmitCVFileChecksumOffsetDirective(unsigned FileNo) { + OS << "\t.cv_filechecksumoffset\t" << FileNo; + EmitEOL(); +} + +void MCAsmStreamer::EmitCVFPOData(const MCSymbol *ProcSym, SMLoc L) { + OS << "\t.cv_fpo_data\t"; + ProcSym->print(OS, MAI); + EmitEOL(); +} + void MCAsmStreamer::EmitIdent(StringRef IdentString) { assert(MAI->hasIdentDirective() && ".ident directive not supported"); OS << "\t.ident\t"; @@ -1263,12 +1319,17 @@ void MCAsmStreamer::EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { void MCAsmStreamer::EmitRegisterName(int64_t Register) { if (!MAI->useDwarfRegNumForCFI()) { + // User .cfi_* directives can use arbitrary DWARF register numbers, not + // just ones that map to LLVM register numbers and have known names. + // Fall back to using the original number directly if no name is known. const MCRegisterInfo *MRI = getContext().getRegisterInfo(); - unsigned LLVMRegister = MRI->getLLVMRegNum(Register, true); - InstPrinter->printRegName(OS, LLVMRegister); - } else { - OS << Register; + int LLVMRegister = MRI->getLLVMRegNumFromEH(Register); + if (LLVMRegister != -1) { + InstPrinter->printRegName(OS, LLVMRegister); + return; + } } + OS << Register; } void MCAsmStreamer::EmitCFIDefCfa(int64_t Register, int64_t Offset) { @@ -1353,6 +1414,13 @@ void MCAsmStreamer::EmitCFIRestoreState() { EmitEOL(); } +void MCAsmStreamer::EmitCFIRestore(int64_t Register) { + MCStreamer::EmitCFIRestore(Register); + OS << "\t.cfi_restore "; + EmitRegisterName(Register); + EmitEOL(); +} + void MCAsmStreamer::EmitCFISameValue(int64_t Register) { MCStreamer::EmitCFISameValue(Register); OS << "\t.cfi_same_value "; @@ -1398,38 +1466,44 @@ void MCAsmStreamer::EmitCFIWindowSave() { EmitEOL(); } -void MCAsmStreamer::EmitWinCFIStartProc(const MCSymbol *Symbol) { - MCStreamer::EmitWinCFIStartProc(Symbol); +void MCAsmStreamer::EmitCFIReturnColumn(int64_t Register) { + MCStreamer::EmitCFIReturnColumn(Register); + OS << "\t.cfi_return_column " << Register; + EmitEOL(); +} + +void MCAsmStreamer::EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) { + MCStreamer::EmitWinCFIStartProc(Symbol, Loc); OS << ".seh_proc "; Symbol->print(OS, MAI); EmitEOL(); } -void MCAsmStreamer::EmitWinCFIEndProc() { - MCStreamer::EmitWinCFIEndProc(); +void MCAsmStreamer::EmitWinCFIEndProc(SMLoc Loc) { + MCStreamer::EmitWinCFIEndProc(Loc); OS << "\t.seh_endproc"; EmitEOL(); } -void MCAsmStreamer::EmitWinCFIStartChained() { - MCStreamer::EmitWinCFIStartChained(); +void MCAsmStreamer::EmitWinCFIStartChained(SMLoc Loc) { + MCStreamer::EmitWinCFIStartChained(Loc); OS << "\t.seh_startchained"; EmitEOL(); } -void MCAsmStreamer::EmitWinCFIEndChained() { - MCStreamer::EmitWinCFIEndChained(); +void MCAsmStreamer::EmitWinCFIEndChained(SMLoc Loc) { + MCStreamer::EmitWinCFIEndChained(Loc); OS << "\t.seh_endchained"; EmitEOL(); } void MCAsmStreamer::EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, - bool Except) { - MCStreamer::EmitWinEHHandler(Sym, Unwind, Except); + bool Except, SMLoc Loc) { + MCStreamer::EmitWinEHHandler(Sym, Unwind, Except, Loc); OS << "\t.seh_handler "; Sym->print(OS, MAI); @@ -1440,8 +1514,8 @@ void MCAsmStreamer::EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, EmitEOL(); } -void MCAsmStreamer::EmitWinEHHandlerData() { - MCStreamer::EmitWinEHHandlerData(); +void MCAsmStreamer::EmitWinEHHandlerData(SMLoc Loc) { + MCStreamer::EmitWinEHHandlerData(Loc); // Switch sections. Don't call SwitchSection directly, because that will // cause the section switch to be visible in the emitted assembly. @@ -1456,43 +1530,46 @@ void MCAsmStreamer::EmitWinEHHandlerData() { EmitEOL(); } -void MCAsmStreamer::EmitWinCFIPushReg(unsigned Register) { - MCStreamer::EmitWinCFIPushReg(Register); +void MCAsmStreamer::EmitWinCFIPushReg(unsigned Register, SMLoc Loc) { + MCStreamer::EmitWinCFIPushReg(Register, Loc); OS << "\t.seh_pushreg " << Register; EmitEOL(); } -void MCAsmStreamer::EmitWinCFISetFrame(unsigned Register, unsigned Offset) { - MCStreamer::EmitWinCFISetFrame(Register, Offset); +void MCAsmStreamer::EmitWinCFISetFrame(unsigned Register, unsigned Offset, + SMLoc Loc) { + MCStreamer::EmitWinCFISetFrame(Register, Offset, Loc); OS << "\t.seh_setframe " << Register << ", " << Offset; EmitEOL(); } -void MCAsmStreamer::EmitWinCFIAllocStack(unsigned Size) { - MCStreamer::EmitWinCFIAllocStack(Size); +void MCAsmStreamer::EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) { + MCStreamer::EmitWinCFIAllocStack(Size, Loc); OS << "\t.seh_stackalloc " << Size; EmitEOL(); } -void MCAsmStreamer::EmitWinCFISaveReg(unsigned Register, unsigned Offset) { - MCStreamer::EmitWinCFISaveReg(Register, Offset); +void MCAsmStreamer::EmitWinCFISaveReg(unsigned Register, unsigned Offset, + SMLoc Loc) { + MCStreamer::EmitWinCFISaveReg(Register, Offset, Loc); OS << "\t.seh_savereg " << Register << ", " << Offset; EmitEOL(); } -void MCAsmStreamer::EmitWinCFISaveXMM(unsigned Register, unsigned Offset) { - MCStreamer::EmitWinCFISaveXMM(Register, Offset); +void MCAsmStreamer::EmitWinCFISaveXMM(unsigned Register, unsigned Offset, + SMLoc Loc) { + MCStreamer::EmitWinCFISaveXMM(Register, Offset, Loc); OS << "\t.seh_savexmm " << Register << ", " << Offset; EmitEOL(); } -void MCAsmStreamer::EmitWinCFIPushFrame(bool Code) { - MCStreamer::EmitWinCFIPushFrame(Code); +void MCAsmStreamer::EmitWinCFIPushFrame(bool Code, SMLoc Loc) { + MCStreamer::EmitWinCFIPushFrame(Code, Loc); OS << "\t.seh_pushframe"; if (Code) @@ -1500,8 +1577,8 @@ void MCAsmStreamer::EmitWinCFIPushFrame(bool Code) { EmitEOL(); } -void MCAsmStreamer::EmitWinCFIEndProlog() { - MCStreamer::EmitWinCFIEndProlog(); +void MCAsmStreamer::EmitWinCFIEndProlog(SMLoc Loc) { + MCStreamer::EmitWinCFIEndProlog(Loc); OS << "\t.seh_endprologue"; EmitEOL(); @@ -1583,8 +1660,8 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst, } } OS << "]"; - // If we are not going to add fixup or schedul comments after this point then - // we have to end the current comment line with "\n". + // If we are not going to add fixup or schedule comments after this point + // then we have to end the current comment line with "\n". if (Fixups.size() || !PrintSchedInfo) OS << "\n"; diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index eaf6f19326eb..01d165944bec 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -68,6 +68,10 @@ STATISTIC(FragmentLayouts, "Number of fragment layouts"); STATISTIC(ObjectBytes, "Number of emitted object file bytes"); STATISTIC(RelaxationSteps, "Number of assembler layout and relaxation steps"); STATISTIC(RelaxedInstructions, "Number of relaxed instructions"); +STATISTIC(PaddingFragmentsRelaxations, + "Number of Padding Fragments relaxations"); +STATISTIC(PaddingFragmentsBytes, + "Total size of all padding from adding Fragments"); } // end namespace stats } // end anonymous namespace @@ -84,7 +88,7 @@ MCAssembler::MCAssembler(MCContext &Context, MCAsmBackend &Backend, : Context(Context), Backend(Backend), Emitter(Emitter), Writer(Writer), BundleAlignSize(0), RelaxAll(false), SubsectionsViaSymbols(false), IncrementalLinkerCompatible(false), ELFHeaderEFlags(0) { - VersionMinInfo.Major = 0; // Major version == 0 for "none specified" + VersionInfo.Major = 0; // Major version == 0 for "none specified" } MCAssembler::~MCAssembler() = default; @@ -103,7 +107,7 @@ void MCAssembler::reset() { IncrementalLinkerCompatible = false; ELFHeaderEFlags = 0; LOHContainer.reset(); - VersionMinInfo.Major = 0; + VersionInfo.Major = 0; // reset objects owned by us getBackend().reset(); @@ -283,7 +287,10 @@ uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, case MCFragment::FT_LEB: return cast<MCLEBFragment>(F).getContents().size(); - case MCFragment::FT_SafeSEH: + case MCFragment::FT_Padding: + return cast<MCPaddingFragment>(F).getSize(); + + case MCFragment::FT_SymbolId: return 4; case MCFragment::FT_Align: { @@ -549,8 +556,15 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, break; } - case MCFragment::FT_SafeSEH: { - const MCSafeSEHFragment &SF = cast<MCSafeSEHFragment>(F); + case MCFragment::FT_Padding: { + if (!Asm.getBackend().writeNopData(FragmentSize, OW)) + report_fatal_error("unable to write nop sequence of " + + Twine(FragmentSize) + " bytes"); + break; + } + + case MCFragment::FT_SymbolId: { + const MCSymbolIdFragment &SF = cast<MCSymbolIdFragment>(F); OW->write32(SF.getSymbol()->getIndex()); break; } @@ -822,6 +836,19 @@ bool MCAssembler::relaxInstruction(MCAsmLayout &Layout, return true; } +bool MCAssembler::relaxPaddingFragment(MCAsmLayout &Layout, + MCPaddingFragment &PF) { + uint64_t OldSize = PF.getSize(); + if (!getBackend().relaxFragment(&PF, Layout)) + return false; + uint64_t NewSize = PF.getSize(); + + ++stats::PaddingFragmentsRelaxations; + stats::PaddingFragmentsBytes += NewSize; + stats::PaddingFragmentsBytes -= OldSize; + return true; +} + bool MCAssembler::relaxLEB(MCAsmLayout &Layout, MCLEBFragment &LF) { uint64_t OldSize = LF.getContents().size(); int64_t Value; @@ -916,6 +943,9 @@ bool MCAssembler::layoutSectionOnce(MCAsmLayout &Layout, MCSection &Sec) { case MCFragment::FT_LEB: RelaxedFrag = relaxLEB(Layout, *cast<MCLEBFragment>(I)); break; + case MCFragment::FT_Padding: + RelaxedFrag = relaxPaddingFragment(Layout, *cast<MCPaddingFragment>(I)); + break; case MCFragment::FT_CVInlineLines: RelaxedFrag = relaxCVInlineLineTable(Layout, *cast<MCCVInlineLineTableFragment>(I)); diff --git a/lib/MC/MCCodePadder.cpp b/lib/MC/MCCodePadder.cpp new file mode 100644 index 000000000000..57547814e595 --- /dev/null +++ b/lib/MC/MCCodePadder.cpp @@ -0,0 +1,371 @@ +//===- MCCodePadder.cpp - Target MC Code Padder ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCCodePadder.h" +#include "llvm/MC/MCObjectStreamer.h" +#include <algorithm> +#include <limits> +#include <numeric> + +using namespace llvm; + +//--------------------------------------------------------------------------- +// MCCodePadder +// + +MCCodePadder::~MCCodePadder() { + for (auto *Policy : CodePaddingPolicies) + delete Policy; +} + +bool MCCodePadder::addPolicy(MCCodePaddingPolicy *Policy) { + assert(Policy && "Policy must be valid"); + return CodePaddingPolicies.insert(Policy).second; +} + +void MCCodePadder::handleBasicBlockStart(MCObjectStreamer *OS, + const MCCodePaddingContext &Context) { + assert(OS != nullptr && "OS must be valid"); + assert(this->OS == nullptr && "Still handling another basic block"); + this->OS = OS; + + ArePoliciesActive = usePoliciesForBasicBlock(Context); + + bool InsertionPoint = basicBlockRequiresInsertionPoint(Context); + assert((!InsertionPoint || + OS->getCurrentFragment()->getKind() != MCFragment::FT_Align) && + "Cannot insert padding nops right after an alignment fragment as it " + "will ruin the alignment"); + + uint64_t PoliciesMask = MCPaddingFragment::PFK_None; + if (ArePoliciesActive) { + PoliciesMask = std::accumulate( + CodePaddingPolicies.begin(), CodePaddingPolicies.end(), + MCPaddingFragment::PFK_None, + [&Context](uint64_t Mask, + const MCCodePaddingPolicy *Policy) -> uint64_t { + return Policy->basicBlockRequiresPaddingFragment(Context) + ? (Mask | Policy->getKindMask()) + : Mask; + }); + } + + if (InsertionPoint || PoliciesMask != MCPaddingFragment::PFK_None) { + MCPaddingFragment *PaddingFragment = OS->getOrCreatePaddingFragment(); + if (InsertionPoint) + PaddingFragment->setAsInsertionPoint(); + PaddingFragment->setPaddingPoliciesMask( + PaddingFragment->getPaddingPoliciesMask() | PoliciesMask); + } +} + +void MCCodePadder::handleBasicBlockEnd(const MCCodePaddingContext &Context) { + assert(this->OS != nullptr && "Not handling a basic block"); + OS = nullptr; +} + +void MCCodePadder::handleInstructionBegin(const MCInst &Inst) { + if (!OS) + return; // instruction was emitted outside a function + + assert(CurrHandledInstFragment == nullptr && "Can't start handling an " + "instruction while still " + "handling another instruction"); + + bool InsertionPoint = instructionRequiresInsertionPoint(Inst); + assert((!InsertionPoint || + OS->getCurrentFragment()->getKind() != MCFragment::FT_Align) && + "Cannot insert padding nops right after an alignment fragment as it " + "will ruin the alignment"); + + uint64_t PoliciesMask = MCPaddingFragment::PFK_None; + if (ArePoliciesActive) { + PoliciesMask = std::accumulate( + CodePaddingPolicies.begin(), CodePaddingPolicies.end(), + MCPaddingFragment::PFK_None, + [&Inst](uint64_t Mask, const MCCodePaddingPolicy *Policy) -> uint64_t { + return Policy->instructionRequiresPaddingFragment(Inst) + ? (Mask | Policy->getKindMask()) + : Mask; + }); + } + MCFragment *CurrFragment = OS->getCurrentFragment(); + // CurrFragment can be a previously created MCPaddingFragment. If so, let's + // update it with the information we have, such as the instruction that it + // should point to. + bool needToUpdateCurrFragment = + CurrFragment != nullptr && + CurrFragment->getKind() == MCFragment::FT_Padding; + if (InsertionPoint || PoliciesMask != MCPaddingFragment::PFK_None || + needToUpdateCurrFragment) { + // temporarily holding the fragment as CurrHandledInstFragment, to be + // updated after the instruction will be written + CurrHandledInstFragment = OS->getOrCreatePaddingFragment(); + if (InsertionPoint) + CurrHandledInstFragment->setAsInsertionPoint(); + CurrHandledInstFragment->setPaddingPoliciesMask( + CurrHandledInstFragment->getPaddingPoliciesMask() | PoliciesMask); + } +} + +void MCCodePadder::handleInstructionEnd(const MCInst &Inst) { + if (!OS) + return; // instruction was emitted outside a function + if (CurrHandledInstFragment == nullptr) + return; + + MCFragment *InstFragment = OS->getCurrentFragment(); + if (MCDataFragment *InstDataFragment = + dyn_cast_or_null<MCDataFragment>(InstFragment)) + // Inst is a fixed size instruction and was encoded into a MCDataFragment. + // Let the fragment hold it and its size. Its size is the current size of + // the data fragment, as the padding fragment was inserted right before it + // and nothing was written yet except Inst + CurrHandledInstFragment->setInstAndInstSize( + Inst, InstDataFragment->getContents().size()); + else if (MCRelaxableFragment *InstRelaxableFragment = + dyn_cast_or_null<MCRelaxableFragment>(InstFragment)) + // Inst may be relaxed and its size may vary. + // Let the fragment hold the instruction and the MCRelaxableFragment + // that's holding it. + CurrHandledInstFragment->setInstAndInstFragment(Inst, + InstRelaxableFragment); + else + llvm_unreachable("After encoding an instruction current fragment must be " + "either a MCDataFragment or a MCRelaxableFragment"); + + CurrHandledInstFragment = nullptr; +} + +MCPFRange &MCCodePadder::getJurisdiction(MCPaddingFragment *Fragment, + MCAsmLayout &Layout) { + auto JurisdictionLocation = FragmentToJurisdiction.find(Fragment); + if (JurisdictionLocation != FragmentToJurisdiction.end()) + return JurisdictionLocation->second; + + MCPFRange Jurisdiction; + + // Forward scanning the fragments in this section, starting from the given + // fragments, and adding relevant MCPaddingFragments to the Jurisdiction + for (MCFragment *CurrFragment = Fragment; CurrFragment != nullptr; + CurrFragment = CurrFragment->getNextNode()) { + + MCPaddingFragment *CurrPaddingFragment = + dyn_cast<MCPaddingFragment>(CurrFragment); + if (CurrPaddingFragment == nullptr) + continue; + + if (CurrPaddingFragment != Fragment && + CurrPaddingFragment->isInsertionPoint()) + // Found next insertion point Fragment. From now on it's its jurisdiction. + break; + for (const auto *Policy : CodePaddingPolicies) { + if (CurrPaddingFragment->hasPaddingPolicy(Policy->getKindMask())) { + Jurisdiction.push_back(CurrPaddingFragment); + break; + } + } + } + + auto InsertionResult = + FragmentToJurisdiction.insert(std::make_pair(Fragment, Jurisdiction)); + assert(InsertionResult.second && + "Insertion to FragmentToJurisdiction failed"); + return InsertionResult.first->second; +} + +uint64_t MCCodePadder::getMaxWindowSize(MCPaddingFragment *Fragment, + MCAsmLayout &Layout) { + auto MaxFragmentSizeLocation = FragmentToMaxWindowSize.find(Fragment); + if (MaxFragmentSizeLocation != FragmentToMaxWindowSize.end()) + return MaxFragmentSizeLocation->second; + + MCPFRange &Jurisdiction = getJurisdiction(Fragment, Layout); + uint64_t JurisdictionMask = MCPaddingFragment::PFK_None; + for (const auto *Protege : Jurisdiction) + JurisdictionMask |= Protege->getPaddingPoliciesMask(); + + uint64_t MaxFragmentSize = UINT64_C(0); + for (const auto *Policy : CodePaddingPolicies) + if ((JurisdictionMask & Policy->getKindMask()) != + MCPaddingFragment::PFK_None) + MaxFragmentSize = std::max(MaxFragmentSize, Policy->getWindowSize()); + + auto InsertionResult = + FragmentToMaxWindowSize.insert(std::make_pair(Fragment, MaxFragmentSize)); + assert(InsertionResult.second && + "Insertion to FragmentToMaxWindowSize failed"); + return InsertionResult.first->second; +} + +bool MCCodePadder::relaxFragment(MCPaddingFragment *Fragment, + MCAsmLayout &Layout) { + if (!Fragment->isInsertionPoint()) + return false; + uint64_t OldSize = Fragment->getSize(); + + uint64_t MaxWindowSize = getMaxWindowSize(Fragment, Layout); + if (MaxWindowSize == UINT64_C(0)) + return false; + assert(isPowerOf2_64(MaxWindowSize) && + "MaxWindowSize must be an integer power of 2"); + uint64_t SectionAlignment = Fragment->getParent()->getAlignment(); + assert(isPowerOf2_64(SectionAlignment) && + "SectionAlignment must be an integer power of 2"); + + MCPFRange &Jurisdiction = getJurisdiction(Fragment, Layout); + uint64_t OptimalSize = UINT64_C(0); + double OptimalWeight = std::numeric_limits<double>::max(); + uint64_t MaxFragmentSize = MaxWindowSize - UINT16_C(1); + for (uint64_t Size = UINT64_C(0); Size <= MaxFragmentSize; ++Size) { + Fragment->setSize(Size); + Layout.invalidateFragmentsFrom(Fragment); + double SizeWeight = 0.0; + // The section is guaranteed to be aligned to SectionAlignment, but that + // doesn't guarantee the exact section offset w.r.t. the policies window + // size. + // As a concrete example, the section could be aligned to 16B, but a + // policy's window size can be 32B. That means that the section actual start + // address can either be 0mod32 or 16mod32. The said policy will act + // differently for each case, so we need to take both into consideration. + for (uint64_t Offset = UINT64_C(0); Offset < MaxWindowSize; + Offset += SectionAlignment) { + double OffsetWeight = std::accumulate( + CodePaddingPolicies.begin(), CodePaddingPolicies.end(), 0.0, + [&Jurisdiction, &Offset, &Layout]( + double Weight, const MCCodePaddingPolicy *Policy) -> double { + double PolicyWeight = + Policy->computeRangePenaltyWeight(Jurisdiction, Offset, Layout); + assert(PolicyWeight >= 0.0 && "A penalty weight must be positive"); + return Weight + PolicyWeight; + }); + SizeWeight = std::max(SizeWeight, OffsetWeight); + } + if (SizeWeight < OptimalWeight) { + OptimalWeight = SizeWeight; + OptimalSize = Size; + } + if (OptimalWeight == 0.0) + break; + } + + Fragment->setSize(OptimalSize); + Layout.invalidateFragmentsFrom(Fragment); + return OldSize != OptimalSize; +} + +//--------------------------------------------------------------------------- +// MCCodePaddingPolicy +// + +uint64_t MCCodePaddingPolicy::getNextFragmentOffset(const MCFragment *Fragment, + const MCAsmLayout &Layout) { + assert(Fragment != nullptr && "Fragment cannot be null"); + MCFragment const *NextFragment = Fragment->getNextNode(); + return NextFragment == nullptr + ? Layout.getSectionAddressSize(Fragment->getParent()) + : Layout.getFragmentOffset(NextFragment); +} + +uint64_t +MCCodePaddingPolicy::getFragmentInstByte(const MCPaddingFragment *Fragment, + MCAsmLayout &Layout) const { + uint64_t InstByte = getNextFragmentOffset(Fragment, Layout); + if (InstByteIsLastByte) + InstByte += Fragment->getInstSize() - UINT64_C(1); + return InstByte; +} + +uint64_t +MCCodePaddingPolicy::computeWindowEndAddress(const MCPaddingFragment *Fragment, + uint64_t Offset, + MCAsmLayout &Layout) const { + uint64_t InstByte = getFragmentInstByte(Fragment, Layout); + return alignTo(InstByte + UINT64_C(1) + Offset, WindowSize) - Offset; +} + +double MCCodePaddingPolicy::computeRangePenaltyWeight( + const MCPFRange &Range, uint64_t Offset, MCAsmLayout &Layout) const { + + SmallVector<MCPFRange, 8> Windows; + SmallVector<MCPFRange, 8>::iterator CurrWindowLocation = Windows.end(); + for (const MCPaddingFragment *Fragment : Range) { + if (!Fragment->hasPaddingPolicy(getKindMask())) + continue; + uint64_t FragmentWindowEndAddress = + computeWindowEndAddress(Fragment, Offset, Layout); + if (CurrWindowLocation == Windows.end() || + FragmentWindowEndAddress != + computeWindowEndAddress(*CurrWindowLocation->begin(), Offset, + Layout)) { + // next window is starting + Windows.push_back(MCPFRange()); + CurrWindowLocation = Windows.end() - 1; + } + CurrWindowLocation->push_back(Fragment); + } + + if (Windows.empty()) + return 0.0; + + double RangeWeight = 0.0; + SmallVector<MCPFRange, 8>::iterator I = Windows.begin(); + RangeWeight += computeFirstWindowPenaltyWeight(*I, Offset, Layout); + ++I; + RangeWeight += std::accumulate( + I, Windows.end(), 0.0, + [this, &Layout, &Offset](double Weight, MCPFRange &Window) -> double { + return Weight += computeWindowPenaltyWeight(Window, Offset, Layout); + }); + return RangeWeight; +} + +double MCCodePaddingPolicy::computeFirstWindowPenaltyWeight( + const MCPFRange &Window, uint64_t Offset, MCAsmLayout &Layout) const { + if (Window.empty()) + return 0.0; + uint64_t WindowEndAddress = + computeWindowEndAddress(*Window.begin(), Offset, Layout); + + MCPFRange FullWindowFirstPart; // will hold all the fragments that are in the + // same window as the fragments in the given + // window but their penalty weight should not + // be added + for (const MCFragment *Fragment = (*Window.begin())->getPrevNode(); + Fragment != nullptr; Fragment = Fragment->getPrevNode()) { + const MCPaddingFragment *PaddingNopFragment = + dyn_cast<MCPaddingFragment>(Fragment); + if (PaddingNopFragment == nullptr || + !PaddingNopFragment->hasPaddingPolicy(getKindMask())) + continue; + if (WindowEndAddress != + computeWindowEndAddress(PaddingNopFragment, Offset, Layout)) + break; + + FullWindowFirstPart.push_back(PaddingNopFragment); + } + + std::reverse(FullWindowFirstPart.begin(), FullWindowFirstPart.end()); + double FullWindowFirstPartWeight = + computeWindowPenaltyWeight(FullWindowFirstPart, Offset, Layout); + + MCPFRange FullWindow( + FullWindowFirstPart); // will hold all the fragments that are in the + // same window as the fragments in the given + // window, whether their weight should be added + // or not + FullWindow.append(Window.begin(), Window.end()); + double FullWindowWeight = + computeWindowPenaltyWeight(FullWindow, Offset, Layout); + + assert(FullWindowWeight >= FullWindowFirstPartWeight && + "More fragments necessarily means bigger weight"); + return FullWindowWeight - FullWindowFirstPartWeight; +} diff --git a/lib/MC/MCCodeView.cpp b/lib/MC/MCCodeView.cpp index 92b1e12da552..82b81ccc24da 100644 --- a/lib/MC/MCCodeView.cpp +++ b/lib/MC/MCCodeView.cpp @@ -13,7 +13,7 @@ #include "llvm/MC/MCCodeView.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/BinaryFormat/COFF.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" @@ -39,29 +39,40 @@ CodeViewContext::~CodeViewContext() { /// for it. bool CodeViewContext::isValidFileNumber(unsigned FileNumber) const { unsigned Idx = FileNumber - 1; - if (Idx < Filenames.size()) - return !Filenames[Idx].empty(); + if (Idx < Files.size()) + return Files[Idx].Assigned; return false; } -bool CodeViewContext::addFile(unsigned FileNumber, StringRef Filename) { +bool CodeViewContext::addFile(MCStreamer &OS, unsigned FileNumber, + StringRef Filename, + ArrayRef<uint8_t> ChecksumBytes, + uint8_t ChecksumKind) { assert(FileNumber > 0); - Filename = addToStringTable(Filename); + auto FilenameOffset = addToStringTable(Filename); + Filename = FilenameOffset.first; unsigned Idx = FileNumber - 1; - if (Idx >= Filenames.size()) - Filenames.resize(Idx + 1); + if (Idx >= Files.size()) + Files.resize(Idx + 1); if (Filename.empty()) Filename = "<stdin>"; - if (!Filenames[Idx].empty()) + if (Files[Idx].Assigned) return false; - // FIXME: We should store the string table offset of the filename, rather than - // the filename itself for efficiency. - Filename = addToStringTable(Filename); + FilenameOffset = addToStringTable(Filename); + Filename = FilenameOffset.first; + unsigned Offset = FilenameOffset.second; + + auto ChecksumOffsetSymbol = + OS.getContext().createTempSymbol("checksum_offset", false); + Files[Idx].StringTableOffset = Offset; + Files[Idx].ChecksumTableOffset = ChecksumOffsetSymbol; + Files[Idx].Assigned = true; + Files[Idx].Checksum = ChecksumBytes; + Files[Idx].ChecksumKind = ChecksumKind; - Filenames[Idx] = Filename; return true; } @@ -118,17 +129,18 @@ MCDataFragment *CodeViewContext::getStringTableFragment() { return StrTabFragment; } -StringRef CodeViewContext::addToStringTable(StringRef S) { +std::pair<StringRef, unsigned> CodeViewContext::addToStringTable(StringRef S) { SmallVectorImpl<char> &Contents = getStringTableFragment()->getContents(); auto Insertion = StringTable.insert(std::make_pair(S, unsigned(Contents.size()))); // Return the string from the table, since it is stable. - S = Insertion.first->first(); + std::pair<StringRef, unsigned> Ret = + std::make_pair(Insertion.first->first(), Insertion.first->second); if (Insertion.second) { // The string map key is always null terminated. - Contents.append(S.begin(), S.end() + 1); + Contents.append(Ret.first.begin(), Ret.first.end() + 1); } - return S; + return Ret; } unsigned CodeViewContext::getStringTableOffset(StringRef S) { @@ -165,7 +177,7 @@ void CodeViewContext::emitStringTable(MCObjectStreamer &OS) { void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) { // Do nothing if there are no file checksums. Microsoft's linker rejects empty // CodeView substreams. - if (Filenames.empty()) + if (Files.empty()) return; MCContext &Ctx = OS.getContext(); @@ -176,17 +188,63 @@ void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) { OS.emitAbsoluteSymbolDiff(FileEnd, FileBegin, 4); OS.EmitLabel(FileBegin); + unsigned CurrentOffset = 0; + // Emit an array of FileChecksum entries. We index into this table using the - // user-provided file number. Each entry is currently 8 bytes, as we don't - // emit checksums. - for (StringRef Filename : Filenames) { - OS.EmitIntValue(getStringTableOffset(Filename), 4); - // Zero the next two fields and align back to 4 bytes. This indicates that - // no checksum is present. - OS.EmitIntValue(0, 4); + // user-provided file number. Each entry may be a variable number of bytes + // determined by the checksum kind and size. + for (auto File : Files) { + OS.EmitAssignment(File.ChecksumTableOffset, + MCConstantExpr::create(CurrentOffset, Ctx)); + CurrentOffset += 4; // String table offset. + if (!File.ChecksumKind) { + CurrentOffset += + 4; // One byte each for checksum size and kind, then align to 4 bytes. + } else { + CurrentOffset += 2; // One byte each for checksum size and kind. + CurrentOffset += File.Checksum.size(); + CurrentOffset = alignTo(CurrentOffset, 4); + } + + OS.EmitIntValue(File.StringTableOffset, 4); + + if (!File.ChecksumKind) { + // There is no checksum. Therefore zero the next two fields and align + // back to 4 bytes. + OS.EmitIntValue(0, 4); + continue; + } + OS.EmitIntValue(static_cast<uint8_t>(File.Checksum.size()), 1); + OS.EmitIntValue(File.ChecksumKind, 1); + OS.EmitBytes(toStringRef(File.Checksum)); + OS.EmitValueToAlignment(4); } OS.EmitLabel(FileEnd); + + ChecksumOffsetsAssigned = true; +} + +// Output checksum table offset of the given file number. It is possible that +// not all files have been registered yet, and so the offset cannot be +// calculated. In this case a symbol representing the offset is emitted, and +// the value of this symbol will be fixed up at a later time. +void CodeViewContext::emitFileChecksumOffset(MCObjectStreamer &OS, + unsigned FileNo) { + unsigned Idx = FileNo - 1; + + if (Idx >= Files.size()) + Files.resize(Idx + 1); + + if (ChecksumOffsetsAssigned) { + OS.EmitSymbolValue(Files[Idx].ChecksumTableOffset, 4); + return; + } + + const MCSymbolRefExpr *SRE = + MCSymbolRefExpr::create(Files[Idx].ChecksumTableOffset, OS.getContext()); + + OS.EmitValueImpl(SRE, 4); } void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS, @@ -219,9 +277,12 @@ void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS, return Loc.getFileNum() != CurFileNum; }); unsigned EntryCount = FileSegEnd - I; - OS.AddComment("Segment for file '" + Twine(Filenames[CurFileNum - 1]) + - "' begins"); - OS.EmitIntValue(8 * (CurFileNum - 1), 4); + OS.AddComment( + "Segment for file '" + + Twine(getStringTableFragment() + ->getContents()[Files[CurFileNum - 1].StringTableOffset]) + + "' begins"); + OS.EmitCVFileChecksumOffsetDirective(CurFileNum); OS.EmitIntValue(EntryCount, 4); uint32_t SegmentSize = 12; SegmentSize += 8 * EntryCount; @@ -401,9 +462,10 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout, HaveOpenRange = true; if (CurSourceLoc.File != LastSourceLoc.File) { - // File ids are 1 based, and each file checksum table entry is 8 bytes - // long. See emitFileChecksums above. - unsigned FileOffset = 8 * (CurSourceLoc.File - 1); + unsigned FileOffset = static_cast<const MCConstantExpr *>( + Files[CurSourceLoc.File - 1] + .ChecksumTableOffset->getVariableValue()) + ->getValue(); compressAnnotation(BinaryAnnotationsOpCode::ChangeFile, Buffer); compressAnnotation(FileOffset, Buffer); } diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index 48ee84edb096..5c25e902bbe7 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -486,53 +486,17 @@ MCSectionCOFF *MCContext::getAssociativeCOFFSection(MCSectionCOFF *Sec, "", 0, UniqueID); } -void MCContext::renameWasmSection(MCSectionWasm *Section, StringRef Name) { - StringRef GroupName; - assert(!Section->getGroup() && "not yet implemented"); - - unsigned UniqueID = Section->getUniqueID(); - WasmUniquingMap.erase( - WasmSectionKey{Section->getSectionName(), GroupName, UniqueID}); - auto I = WasmUniquingMap.insert(std::make_pair( - WasmSectionKey{Name, GroupName, UniqueID}, - Section)) - .first; - StringRef CachedName = I->first.SectionName; - const_cast<MCSectionWasm *>(Section)->setSectionName(CachedName); -} - -MCSectionWasm *MCContext::createWasmRelSection(const Twine &Name, unsigned Type, - unsigned Flags, - const MCSymbolWasm *Group) { - StringMap<bool>::iterator I; - bool Inserted; - std::tie(I, Inserted) = - RelSecNames.insert(std::make_pair(Name.str(), true)); - - return new (WasmAllocator.Allocate()) - MCSectionWasm(I->getKey(), Type, Flags, SectionKind::getReadOnly(), - Group, ~0, nullptr); -} - -MCSectionWasm *MCContext::getWasmNamedSection(const Twine &Prefix, - const Twine &Suffix, unsigned Type, - unsigned Flags) { - return getWasmSection(Prefix + "." + Suffix, Type, Flags, Suffix); -} - -MCSectionWasm *MCContext::getWasmSection(const Twine &Section, unsigned Type, - unsigned Flags, +MCSectionWasm *MCContext::getWasmSection(const Twine &Section, SectionKind K, const Twine &Group, unsigned UniqueID, const char *BeginSymName) { MCSymbolWasm *GroupSym = nullptr; if (!Group.isTriviallyEmpty() && !Group.str().empty()) GroupSym = cast<MCSymbolWasm>(getOrCreateSymbol(Group)); - return getWasmSection(Section, Type, Flags, GroupSym, UniqueID, BeginSymName); + return getWasmSection(Section, K, GroupSym, UniqueID, BeginSymName); } -MCSectionWasm *MCContext::getWasmSection(const Twine &Section, unsigned Type, - unsigned Flags, +MCSectionWasm *MCContext::getWasmSection(const Twine &Section, SectionKind Kind, const MCSymbolWasm *GroupSym, unsigned UniqueID, const char *BeginSymName) { @@ -548,14 +512,12 @@ MCSectionWasm *MCContext::getWasmSection(const Twine &Section, unsigned Type, StringRef CachedName = Entry.first.SectionName; - SectionKind Kind = SectionKind::getText(); - MCSymbol *Begin = nullptr; if (BeginSymName) Begin = createTempSymbol(BeginSymName, false); MCSectionWasm *Result = new (WasmAllocator.Allocate()) - MCSectionWasm(CachedName, Type, Flags, Kind, GroupSym, UniqueID, Begin); + MCSectionWasm(CachedName, Kind, GroupSym, UniqueID, Begin); Entry.second = Result; return Result; } diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index a2beee32f2cb..9e5d9ff73c76 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -257,6 +257,66 @@ static void emitAbsValue(MCStreamer &OS, const MCExpr *Value, unsigned Size) { OS.EmitValue(ABS, Size); } +static void +emitV2FileDirTables(MCStreamer *MCOS, + const SmallVectorImpl<std::string> &MCDwarfDirs, + const SmallVectorImpl<MCDwarfFile> &MCDwarfFiles) { + // First the directory table. + for (auto Dir : MCDwarfDirs) { + MCOS->EmitBytes(Dir); // The DirectoryName, and... + MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. + } + MCOS->EmitIntValue(0, 1); // Terminate the directory list. + + // Second the file table. + for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { + assert(!MCDwarfFiles[i].Name.empty()); + MCOS->EmitBytes(MCDwarfFiles[i].Name); // FileName and... + MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. + MCOS->EmitULEB128IntValue(MCDwarfFiles[i].DirIndex); // Directory number. + MCOS->EmitIntValue(0, 1); // Last modification timestamp (always 0). + MCOS->EmitIntValue(0, 1); // File size (always 0). + } + MCOS->EmitIntValue(0, 1); // Terminate the file list. +} + +static void +emitV5FileDirTables(MCStreamer *MCOS, + const SmallVectorImpl<std::string> &MCDwarfDirs, + const SmallVectorImpl<MCDwarfFile> &MCDwarfFiles, + StringRef CompilationDir) { + // The directory format, which is just inline null-terminated strings. + MCOS->EmitIntValue(1, 1); + MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_path); + MCOS->EmitULEB128IntValue(dwarf::DW_FORM_string); + // Then the list of directory paths. CompilationDir comes first. + MCOS->EmitULEB128IntValue(MCDwarfDirs.size() + 1); + MCOS->EmitBytes(CompilationDir); + MCOS->EmitBytes(StringRef("\0", 1)); + for (auto Dir : MCDwarfDirs) { + MCOS->EmitBytes(Dir); // The DirectoryName, and... + MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. + } + + // The file format, which is the inline null-terminated filename and a + // directory index. We don't track file size/timestamp so don't emit them + // in the v5 table. + // FIXME: Arrange to emit MD5 signatures for the source files. + MCOS->EmitIntValue(2, 1); + MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_path); + MCOS->EmitULEB128IntValue(dwarf::DW_FORM_string); + MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_directory_index); + MCOS->EmitULEB128IntValue(dwarf::DW_FORM_udata); + // Then the list of file names. These start at 1 for some reason. + MCOS->EmitULEB128IntValue(MCDwarfFiles.size() - 1); + for (unsigned i = 1; i < MCDwarfFiles.size(); ++i) { + assert(!MCDwarfFiles[i].Name.empty()); + MCOS->EmitBytes(MCDwarfFiles[i].Name); // FileName and... + MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. + MCOS->EmitULEB128IntValue(MCDwarfFiles[i].DirIndex); // Directory number. + } +} + std::pair<MCSymbol *, MCSymbol *> MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, ArrayRef<char> StandardOpcodeLengths) const { @@ -277,22 +337,41 @@ MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, emitAbsValue(*MCOS, MakeStartMinusEndExpr(*MCOS, *LineStartSym, *LineEndSym, 4), 4); - // Next 2 bytes is the Version, which is Dwarf 2. - MCOS->EmitIntValue(2, 2); + // 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 + // comes out. + unsigned PreHeaderLengthBytes = 4 + 2; + + // In v5, we get address info next. + if (LineTableVersion >= 5) { + MCOS->EmitIntValue(context.getAsmInfo()->getCodePointerSize(), 1); + MCOS->EmitIntValue(0, 1); // Segment selector; same as EmitGenDwarfAranges. + PreHeaderLengthBytes += 2; + } // Create a symbol for the end of the prologue (to be set when we get there). MCSymbol *ProEndSym = context.createTempSymbol(); // Lprologue_end - // Length of the prologue, is the next 4 bytes. Which is the start of the - // section to the end of the prologue. Not including the 4 bytes for the - // total length, the 2 bytes for the version, and these 4 bytes for the - // length of the prologue. - emitAbsValue( - *MCOS, - MakeStartMinusEndExpr(*MCOS, *LineStartSym, *ProEndSym, (4 + 2 + 4)), 4); + // Length of the prologue, is the next 4 bytes. This is actually the length + // from after the length word, to the end of the prologue. + emitAbsValue(*MCOS, + MakeStartMinusEndExpr(*MCOS, *LineStartSym, *ProEndSym, + (PreHeaderLengthBytes + 4)), + 4); // Parameters of the state machine, are next. MCOS->EmitIntValue(context.getAsmInfo()->getMinInstAlignment(), 1); + // maximum_operations_per_instruction + // For non-VLIW architectures this field is always 1. + // FIXME: VLIW architectures need to update this field accordingly. + if (LineTableVersion >= 4) + MCOS->EmitIntValue(1, 1); MCOS->EmitIntValue(DWARF2_LINE_DEFAULT_IS_STMT, 1); MCOS->EmitIntValue(Params.DWARF2LineBase, 1); MCOS->EmitIntValue(Params.DWARF2LineRange, 1); @@ -302,26 +381,12 @@ MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, for (char Length : StandardOpcodeLengths) MCOS->EmitIntValue(Length, 1); - // Put out the directory and file tables. - - // First the directory table. - for (unsigned i = 0; i < MCDwarfDirs.size(); i++) { - MCOS->EmitBytes(MCDwarfDirs[i]); // the DirectoryName - MCOS->EmitBytes(StringRef("\0", 1)); // the null term. of the string - } - MCOS->EmitIntValue(0, 1); // Terminate the directory list - - // Second the file table. - for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { - assert(!MCDwarfFiles[i].Name.empty()); - MCOS->EmitBytes(MCDwarfFiles[i].Name); // FileName - MCOS->EmitBytes(StringRef("\0", 1)); // the null term. of the string - // the Directory num - MCOS->EmitULEB128IntValue(MCDwarfFiles[i].DirIndex); - MCOS->EmitIntValue(0, 1); // last modification timestamp (always 0) - MCOS->EmitIntValue(0, 1); // filesize (always 0) - } - MCOS->EmitIntValue(0, 1); // Terminate the file list + // Put out the directory and file tables. The formats vary depending on + // the version. + if (LineTableVersion >= 5) + emitV5FileDirTables(MCOS, MCDwarfDirs, MCDwarfFiles, CompilationDir); + else + emitV2FileDirTables(MCOS, MCDwarfDirs, MCDwarfFiles); // This is the end of the prologue, so set the value of the symbol at the // end of the prologue (that was used in a previous expression). @@ -370,7 +435,8 @@ unsigned MCDwarfLineTableHeader::getFile(StringRef &Directory, return IterBool.first->second; } // Make space for this FileNumber in the MCDwarfFiles vector if needed. - MCDwarfFiles.resize(FileNumber + 1); + if (FileNumber >= MCDwarfFiles.size()) + MCDwarfFiles.resize(FileNumber + 1); // Get the new MCDwarfFile slot for this FileNumber. MCDwarfFile &File = MCDwarfFiles[FileNumber]; @@ -1034,10 +1100,7 @@ public: /// Emit the unwind information in a compact way. void EmitCompactUnwind(const MCDwarfFrameInfo &frame); - const MCSymbol &EmitCIE(const MCSymbol *personality, - unsigned personalityEncoding, const MCSymbol *lsda, - bool IsSignalFrame, unsigned lsdaEncoding, - bool IsSimple); + const MCSymbol &EmitCIE(const MCDwarfFrameInfo &F); void EmitFDE(const MCSymbol &cieStart, const MCDwarfFrameInfo &frame, bool LastInSection, const MCSymbol &SectionStart); void EmitCFIInstructions(ArrayRef<MCCFIInstruction> Instrs, @@ -1060,8 +1123,8 @@ void FrameEmitterImpl::EmitCFIInstruction(const MCCFIInstruction &Instr) { unsigned Reg1 = Instr.getRegister(); unsigned Reg2 = Instr.getRegister2(); if (!IsEH) { - Reg1 = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg1, true), false); - Reg2 = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg2, true), false); + Reg1 = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg1); + Reg2 = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg2); } Streamer.EmitIntValue(dwarf::DW_CFA_register, 1); Streamer.EmitULEB128IntValue(Reg1); @@ -1097,7 +1160,7 @@ void FrameEmitterImpl::EmitCFIInstruction(const MCCFIInstruction &Instr) { case MCCFIInstruction::OpDefCfa: { unsigned Reg = Instr.getRegister(); if (!IsEH) - Reg = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg, true), false); + Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg); Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa, 1); Streamer.EmitULEB128IntValue(Reg); CFAOffset = -Instr.getOffset(); @@ -1108,7 +1171,7 @@ void FrameEmitterImpl::EmitCFIInstruction(const MCCFIInstruction &Instr) { case MCCFIInstruction::OpDefCfaRegister: { unsigned Reg = Instr.getRegister(); if (!IsEH) - Reg = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg, true), false); + Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg); Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_register, 1); Streamer.EmitULEB128IntValue(Reg); @@ -1121,7 +1184,7 @@ void FrameEmitterImpl::EmitCFIInstruction(const MCCFIInstruction &Instr) { unsigned Reg = Instr.getRegister(); if (!IsEH) - Reg = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg, true), false); + Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg); int Offset = Instr.getOffset(); if (IsRelative) @@ -1157,7 +1220,7 @@ void FrameEmitterImpl::EmitCFIInstruction(const MCCFIInstruction &Instr) { case MCCFIInstruction::OpRestore: { unsigned Reg = Instr.getRegister(); if (!IsEH) - Reg = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg, true), false); + Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg); Streamer.EmitIntValue(dwarf::DW_CFA_restore | Reg, 1); return; } @@ -1273,12 +1336,7 @@ static unsigned getCIEVersion(bool IsEH, unsigned DwarfVersion) { llvm_unreachable("Unknown version"); } -const MCSymbol &FrameEmitterImpl::EmitCIE(const MCSymbol *personality, - unsigned personalityEncoding, - const MCSymbol *lsda, - bool IsSignalFrame, - unsigned lsdaEncoding, - bool IsSimple) { +const MCSymbol &FrameEmitterImpl::EmitCIE(const MCDwarfFrameInfo &Frame) { MCContext &context = Streamer.getContext(); const MCRegisterInfo *MRI = context.getRegisterInfo(); const MCObjectFileInfo *MOFI = context.getObjectFileInfo(); @@ -1305,12 +1363,12 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(const MCSymbol *personality, SmallString<8> Augmentation; if (IsEH) { Augmentation += "z"; - if (personality) + if (Frame.Personality) Augmentation += "P"; - if (lsda) + if (Frame.Lsda) Augmentation += "L"; Augmentation += "R"; - if (IsSignalFrame) + if (Frame.IsSignalFrame) Augmentation += "S"; Streamer.EmitBytes(Augmentation); } @@ -1331,26 +1389,29 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(const MCSymbol *personality, Streamer.EmitSLEB128IntValue(getDataAlignmentFactor(Streamer)); // Return Address Register + unsigned RAReg = Frame.RAReg; + if (RAReg == static_cast<unsigned>(INT_MAX)) + RAReg = MRI->getDwarfRegNum(MRI->getRARegister(), IsEH); + if (CIEVersion == 1) { - assert(MRI->getRARegister() <= 255 && + assert(RAReg <= 255 && "DWARF 2 encodes return_address_register in one byte"); - Streamer.EmitIntValue(MRI->getDwarfRegNum(MRI->getRARegister(), IsEH), 1); + Streamer.EmitIntValue(RAReg, 1); } else { - Streamer.EmitULEB128IntValue( - MRI->getDwarfRegNum(MRI->getRARegister(), IsEH)); + Streamer.EmitULEB128IntValue(RAReg); } // Augmentation Data Length (optional) - unsigned augmentationLength = 0; if (IsEH) { - if (personality) { + if (Frame.Personality) { // Personality Encoding augmentationLength += 1; // Personality - augmentationLength += getSizeForEncoding(Streamer, personalityEncoding); + augmentationLength += + getSizeForEncoding(Streamer, Frame.PersonalityEncoding); } - if (lsda) + if (Frame.Lsda) augmentationLength += 1; // Encoding of the FDE pointers augmentationLength += 1; @@ -1358,15 +1419,15 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(const MCSymbol *personality, Streamer.EmitULEB128IntValue(augmentationLength); // Augmentation Data (optional) - if (personality) { + if (Frame.Personality) { // Personality Encoding - emitEncodingByte(Streamer, personalityEncoding); + emitEncodingByte(Streamer, Frame.PersonalityEncoding); // Personality - EmitPersonality(Streamer, *personality, personalityEncoding); + EmitPersonality(Streamer, *Frame.Personality, Frame.PersonalityEncoding); } - if (lsda) - emitEncodingByte(Streamer, lsdaEncoding); + if (Frame.Lsda) + emitEncodingByte(Streamer, Frame.LsdaEncoding); // Encoding of the FDE pointers emitEncodingByte(Streamer, MOFI->getFDEEncoding()); @@ -1375,7 +1436,7 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(const MCSymbol *personality, // Initial Instructions const MCAsmInfo *MAI = context.getAsmInfo(); - if (!IsSimple) { + if (!Frame.IsSimple) { const std::vector<MCCFIInstruction> &Instructions = MAI->getInitialFrameState(); EmitCFIInstructions(Instructions, nullptr); @@ -1463,24 +1524,32 @@ namespace { struct CIEKey { static const CIEKey getEmptyKey() { - return CIEKey(nullptr, 0, -1, false, false); + return CIEKey(nullptr, 0, -1, false, false, static_cast<unsigned>(INT_MAX)); } static const CIEKey getTombstoneKey() { - return CIEKey(nullptr, -1, 0, false, false); + return CIEKey(nullptr, -1, 0, false, false, static_cast<unsigned>(INT_MAX)); } CIEKey(const MCSymbol *Personality, unsigned PersonalityEncoding, - unsigned LsdaEncoding, bool IsSignalFrame, bool IsSimple) + unsigned LSDAEncoding, bool IsSignalFrame, bool IsSimple, + unsigned RAReg) : Personality(Personality), PersonalityEncoding(PersonalityEncoding), - LsdaEncoding(LsdaEncoding), IsSignalFrame(IsSignalFrame), - IsSimple(IsSimple) {} + LsdaEncoding(LSDAEncoding), IsSignalFrame(IsSignalFrame), + IsSimple(IsSimple), RAReg(RAReg) {} + + explicit CIEKey(const MCDwarfFrameInfo &Frame) + : Personality(Frame.Personality), + PersonalityEncoding(Frame.PersonalityEncoding), + LsdaEncoding(Frame.LsdaEncoding), IsSignalFrame(Frame.IsSignalFrame), + IsSimple(Frame.IsSimple), RAReg(Frame.RAReg) {} const MCSymbol *Personality; unsigned PersonalityEncoding; unsigned LsdaEncoding; bool IsSignalFrame; bool IsSimple; + unsigned RAReg; }; } // end anonymous namespace @@ -1494,7 +1563,7 @@ template <> struct DenseMapInfo<CIEKey> { static unsigned getHashValue(const CIEKey &Key) { return static_cast<unsigned>( hash_combine(Key.Personality, Key.PersonalityEncoding, Key.LsdaEncoding, - Key.IsSignalFrame, Key.IsSimple)); + Key.IsSignalFrame, Key.IsSimple, Key.RAReg)); } static bool isEqual(const CIEKey &LHS, const CIEKey &RHS) { @@ -1502,7 +1571,8 @@ template <> struct DenseMapInfo<CIEKey> { LHS.PersonalityEncoding == RHS.PersonalityEncoding && LHS.LsdaEncoding == RHS.LsdaEncoding && LHS.IsSignalFrame == RHS.IsSignalFrame && - LHS.IsSimple == RHS.IsSimple; + LHS.IsSimple == RHS.IsSimple && + LHS.RAReg == RHS.RAReg; } }; @@ -1559,13 +1629,10 @@ void MCDwarfFrameEmitter::Emit(MCObjectStreamer &Streamer, MCAsmBackend *MAB, // of by the compact unwind encoding. continue; - CIEKey Key(Frame.Personality, Frame.PersonalityEncoding, - Frame.LsdaEncoding, Frame.IsSignalFrame, Frame.IsSimple); + CIEKey Key(Frame); const MCSymbol *&CIEStart = IsEH ? CIEStarts[Key] : DummyDebugKey; if (!CIEStart) - CIEStart = &Emitter.EmitCIE(Frame.Personality, Frame.PersonalityEncoding, - Frame.Lsda, Frame.IsSignalFrame, - Frame.LsdaEncoding, Frame.IsSimple); + CIEStart = &Emitter.EmitCIE(Frame); Emitter.EmitFDE(*CIEStart, Frame, I == E, *SectionStart); } diff --git a/lib/MC/MCELFObjectTargetWriter.cpp b/lib/MC/MCELFObjectTargetWriter.cpp index 68fb5e7cbb3d..483ee94c0db1 100644 --- a/lib/MC/MCELFObjectTargetWriter.cpp +++ b/lib/MC/MCELFObjectTargetWriter.cpp @@ -11,15 +11,11 @@ using namespace llvm; -MCELFObjectTargetWriter::MCELFObjectTargetWriter(bool Is64Bit_, - uint8_t OSABI_, +MCELFObjectTargetWriter::MCELFObjectTargetWriter(bool Is64Bit_, uint8_t OSABI_, uint16_t EMachine_, - bool HasRelocationAddend_, - bool IsN64_) - : OSABI(OSABI_), EMachine(EMachine_), - HasRelocationAddend(HasRelocationAddend_), Is64Bit(Is64Bit_), - IsN64(IsN64_){ -} + bool HasRelocationAddend_) + : OSABI(OSABI_), EMachine(EMachine_), + HasRelocationAddend(HasRelocationAddend_), Is64Bit(Is64Bit_) {} bool MCELFObjectTargetWriter::needsRelocateWithSymbol(const MCSymbol &Sym, unsigned Type) const { diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 50c1f6e79f8a..366125962a5e 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -39,6 +39,12 @@ using namespace llvm; +MCELFStreamer::MCELFStreamer(MCContext &Context, + std::unique_ptr<MCAsmBackend> TAB, + raw_pwrite_stream &OS, + std::unique_ptr<MCCodeEmitter> Emitter) + : MCObjectStreamer(Context, std::move(TAB), OS, std::move(Emitter)) {} + bool MCELFStreamer::isBundleLocked() const { return getCurrentSectionOnly()->isBundleLocked(); } @@ -62,12 +68,13 @@ void MCELFStreamer::mergeFragment(MCDataFragment *DF, if (RequiredBundlePadding > 0) { SmallString<256> Code; raw_svector_ostream VecOS(Code); - MCObjectWriter *OW = Assembler.getBackend().createObjectWriter(VecOS); + { + auto OW = Assembler.getBackend().createObjectWriter(VecOS); - EF->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding)); + EF->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding)); - Assembler.writeFragmentPadding(*EF, FSize, OW); - delete OW; + Assembler.writeFragmentPadding(*EF, FSize, OW.get()); + } DF->getContents().append(Code.begin(), Code.end()); } @@ -638,10 +645,13 @@ void MCELFStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, llvm_unreachable("ELF doesn't support this directive"); } -MCStreamer *llvm::createELFStreamer(MCContext &Context, MCAsmBackend &MAB, - raw_pwrite_stream &OS, MCCodeEmitter *CE, +MCStreamer *llvm::createELFStreamer(MCContext &Context, + std::unique_ptr<MCAsmBackend> &&MAB, + raw_pwrite_stream &OS, + std::unique_ptr<MCCodeEmitter> &&CE, bool RelaxAll) { - MCELFStreamer *S = new MCELFStreamer(Context, MAB, OS, CE); + MCELFStreamer *S = + new MCELFStreamer(Context, std::move(MAB), OS, std::move(CE)); if (RelaxAll) S->getAssembler().setRelaxAll(true); return S; diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp index 38a8af49c194..f8fff4414f49 100644 --- a/lib/MC/MCExpr.cpp +++ b/lib/MC/MCExpr.cpp @@ -224,6 +224,13 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { case VK_ARM_SBREL: return "sbrel"; case VK_ARM_TLSLDO: return "tlsldo"; case VK_ARM_TLSDESCSEQ: return "tlsdescseq"; + case VK_AVR_NONE: return "none"; + case VK_AVR_LO8: return "lo8"; + case VK_AVR_HI8: return "hi8"; + case VK_AVR_HLO8: return "hlo8"; + case VK_AVR_DIFF8: return "diff8"; + case VK_AVR_DIFF16: return "diff16"; + case VK_AVR_DIFF32: return "diff32"; case VK_PPC_LO: return "l"; case VK_PPC_HI: return "h"; case VK_PPC_HA: return "ha"; @@ -389,6 +396,9 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) { .Case("prel31", VK_ARM_PREL31) .Case("sbrel", VK_ARM_SBREL) .Case("tlsldo", VK_ARM_TLSLDO) + .Case("lo8", VK_AVR_LO8) + .Case("hi8", VK_AVR_HI8) + .Case("hlo8", VK_AVR_HLO8) .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO) .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI) .Case("rel32@lo", VK_AMDGPU_REL32_LO) diff --git a/lib/MC/MCFragment.cpp b/lib/MC/MCFragment.cpp index 6e0249377a89..1aed50aaeb77 100644 --- a/lib/MC/MCFragment.cpp +++ b/lib/MC/MCFragment.cpp @@ -80,7 +80,7 @@ uint64_t MCAsmLayout::getFragmentOffset(const MCFragment *F) const { return F->Offset; } -// Simple getSymbolOffset helper for the non-varibale case. +// Simple getSymbolOffset helper for the non-variable case. static bool getLabelOffset(const MCAsmLayout &Layout, const MCSymbol &S, bool ReportError, uint64_t &Val) { if (!S.getFragment()) { @@ -278,8 +278,11 @@ void MCFragment::destroy() { case FT_LEB: delete cast<MCLEBFragment>(this); return; - case FT_SafeSEH: - delete cast<MCSafeSEHFragment>(this); + case FT_Padding: + delete cast<MCPaddingFragment>(this); + return; + case FT_SymbolId: + delete cast<MCSymbolIdFragment>(this); return; case FT_CVInlineLines: delete cast<MCCVInlineLineTableFragment>(this); @@ -322,7 +325,8 @@ LLVM_DUMP_METHOD void MCFragment::dump() const { case MCFragment::FT_Dwarf: OS << "MCDwarfFragment"; break; case MCFragment::FT_DwarfFrame: OS << "MCDwarfCallFrameFragment"; break; case MCFragment::FT_LEB: OS << "MCLEBFragment"; break; - case MCFragment::FT_SafeSEH: OS << "MCSafeSEHFragment"; break; + case MCFragment::FT_Padding: OS << "MCPaddingFragment"; break; + case MCFragment::FT_SymbolId: OS << "MCSymbolIdFragment"; break; case MCFragment::FT_CVInlineLines: OS << "MCCVInlineLineTableFragment"; break; case MCFragment::FT_CVDefRange: OS << "MCCVDefRangeTableFragment"; break; case MCFragment::FT_Dummy: OS << "MCDummyFragment"; break; @@ -419,8 +423,21 @@ LLVM_DUMP_METHOD void MCFragment::dump() const { OS << " Value:" << LF->getValue() << " Signed:" << LF->isSigned(); break; } - case MCFragment::FT_SafeSEH: { - const MCSafeSEHFragment *F = cast<MCSafeSEHFragment>(this); + case MCFragment::FT_Padding: { + const MCPaddingFragment *F = cast<MCPaddingFragment>(this); + OS << "\n "; + OS << " PaddingPoliciesMask:" << F->getPaddingPoliciesMask() + << " IsInsertionPoint:" << F->isInsertionPoint() + << " Size:" << F->getSize(); + OS << "\n "; + OS << " Inst:"; + F->getInst().dump_pretty(OS); + OS << " InstSize:" << F->getInstSize(); + OS << "\n "; + break; + } + case MCFragment::FT_SymbolId: { + const MCSymbolIdFragment *F = cast<MCSymbolIdFragment>(this); OS << "\n "; OS << " Sym:" << F->getSymbol(); break; diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 674c7b9bf619..82b75afabb3c 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -62,10 +62,12 @@ private: void EmitDataRegionEnd(); public: - MCMachOStreamer(MCContext &Context, MCAsmBackend &MAB, raw_pwrite_stream &OS, - MCCodeEmitter *Emitter, bool DWARFMustBeAtTheEnd, bool label) - : MCObjectStreamer(Context, MAB, OS, Emitter), LabelSections(label), - DWARFMustBeAtTheEnd(DWARFMustBeAtTheEnd), CreatedADWARFSection(false) {} + MCMachOStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> MAB, + raw_pwrite_stream &OS, std::unique_ptr<MCCodeEmitter> Emitter, + bool DWARFMustBeAtTheEnd, bool label) + : MCObjectStreamer(Context, std::move(MAB), OS, std::move(Emitter)), + LabelSections(label), DWARFMustBeAtTheEnd(DWARFMustBeAtTheEnd), + CreatedADWARFSection(false) {} /// state management void reset() override { @@ -86,6 +88,8 @@ public: 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 EmitThumbFunc(MCSymbol *Func) override; bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override; @@ -263,7 +267,13 @@ void MCMachOStreamer::EmitDataRegion(MCDataRegionType Kind) { void MCMachOStreamer::EmitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor, unsigned Update) { - getAssembler().setVersionMinInfo(Kind, Major, Minor, Update); + getAssembler().setVersionMin(Kind, Major, Minor, Update); +} + +void MCMachOStreamer::EmitBuildVersion(unsigned Platform, unsigned Major, + unsigned Minor, unsigned Update) { + getAssembler().setBuildVersion((MachO::PlatformType)Platform, Major, Minor, + Update); } void MCMachOStreamer::EmitThumbFunc(MCSymbol *Symbol) { @@ -483,32 +493,17 @@ void MCMachOStreamer::FinishImpl() { this->MCObjectStreamer::FinishImpl(); } -MCStreamer *llvm::createMachOStreamer(MCContext &Context, MCAsmBackend &MAB, - raw_pwrite_stream &OS, MCCodeEmitter *CE, +MCStreamer *llvm::createMachOStreamer(MCContext &Context, + std::unique_ptr<MCAsmBackend> &&MAB, + raw_pwrite_stream &OS, + std::unique_ptr<MCCodeEmitter> &&CE, bool RelaxAll, bool DWARFMustBeAtTheEnd, bool LabelSections) { - MCMachOStreamer *S = new MCMachOStreamer(Context, MAB, OS, CE, - DWARFMustBeAtTheEnd, LabelSections); - const Triple &TT = Context.getObjectFileInfo()->getTargetTriple(); - if (TT.isOSDarwin()) { - unsigned Major, Minor, Update; - TT.getOSVersion(Major, Minor, Update); - // If there is a version specified, Major will be non-zero. - if (Major) { - MCVersionMinType VersionType; - if (TT.isWatchOS()) - VersionType = MCVM_WatchOSVersionMin; - else if (TT.isTvOS()) - VersionType = MCVM_TvOSVersionMin; - else if (TT.isMacOSX()) - VersionType = MCVM_OSXVersionMin; - else { - assert(TT.isiOS() && "Must only be iOS platform left"); - VersionType = MCVM_IOSVersionMin; - } - S->EmitVersionMin(VersionType, Major, Minor, Update); - } - } + MCMachOStreamer *S = + new MCMachOStreamer(Context, std::move(MAB), OS, std::move(CE), + DWARFMustBeAtTheEnd, LabelSections); + const Triple &Target = Context.getObjectFileInfo()->getTargetTriple(); + S->EmitVersionForTarget(Target); if (RelaxAll) S->getAssembler().setRelaxAll(true); return S; diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp index 4db9a2c8d8de..ccf658e1d135 100644 --- a/lib/MC/MCNullStreamer.cpp +++ b/lib/MC/MCNullStreamer.cpp @@ -7,9 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/MC/MCContext.h" #include "llvm/MC/MCInst.h" -#include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" diff --git a/lib/MC/MCObjectFileInfo.cpp b/lib/MC/MCObjectFileInfo.cpp index 21c5516785ef..a6b5c43f1d2a 100644 --- a/lib/MC/MCObjectFileInfo.cpp +++ b/lib/MC/MCObjectFileInfo.cpp @@ -185,6 +185,7 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { COFFDebugSymbolsSection = nullptr; COFFDebugTypesSection = nullptr; + COFFGlobalTypeHashesSection = nullptr; if (useCompactUnwind(T)) { CompactUnwindSection = @@ -214,6 +215,10 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { Ctx->getMachOSection("__DWARF", "__apple_types", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "types_begin"); + DwarfSwiftASTSection = + Ctx->getMachOSection("__DWARF", "__swift_ast", MachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfAbbrevSection = Ctx->getMachOSection("__DWARF", "__debug_abbrev", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "section_abbrev"); @@ -274,7 +279,7 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { TLSExtraDataSection = TLSTLVSection; } -void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T) { +void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { switch (T.getArch()) { case Triple::mips: case Triple::mipsel: @@ -286,8 +291,7 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T) { break; case Triple::x86_64: FDECFIEncoding = dwarf::DW_EH_PE_pcrel | - ((CMModel == CodeModel::Large) ? dwarf::DW_EH_PE_sdata8 - : dwarf::DW_EH_PE_sdata4); + (Large ? dwarf::DW_EH_PE_sdata8 : dwarf::DW_EH_PE_sdata4); break; case Triple::bpfel: case Triple::bpfeb: @@ -324,23 +328,18 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T) { break; case Triple::x86_64: if (PositionIndependent) { - PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - ((CMModel == CodeModel::Small || CMModel == CodeModel::Medium) - ? dwarf::DW_EH_PE_sdata4 : dwarf::DW_EH_PE_sdata8); + 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 | - (CMModel == CodeModel::Small - ? dwarf::DW_EH_PE_sdata4 : dwarf::DW_EH_PE_sdata8); + (Large ? dwarf::DW_EH_PE_sdata8 : dwarf::DW_EH_PE_sdata4); TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - ((CMModel == CodeModel::Small || CMModel == CodeModel::Medium) - ? dwarf::DW_EH_PE_sdata4 : dwarf::DW_EH_PE_sdata8); + (Large ? dwarf::DW_EH_PE_sdata8 : dwarf::DW_EH_PE_sdata4); } else { PersonalityEncoding = - (CMModel == CodeModel::Small || CMModel == CodeModel::Medium) - ? dwarf::DW_EH_PE_udata4 : dwarf::DW_EH_PE_absptr; - LSDAEncoding = (CMModel == CodeModel::Small) - ? dwarf::DW_EH_PE_udata4 : dwarf::DW_EH_PE_absptr; - TTypeEncoding = (CMModel == CodeModel::Small) - ? dwarf::DW_EH_PE_udata4 : dwarf::DW_EH_PE_absptr; + 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: @@ -596,6 +595,8 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T) { EHFrameSection = Ctx->getELFSection(".eh_frame", EHSectionType, EHSectionFlags); + + StackSizesSection = Ctx->getELFSection(".stack_sizes", ELF::SHT_PROGBITS, 0); } void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { @@ -655,6 +656,11 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ), SectionKind::getMetadata()); + COFFGlobalTypeHashesSection = Ctx->getCOFFSection( + ".debug$H", + (COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ), + SectionKind::getMetadata()); DwarfAbbrevSection = Ctx->getCOFFSection( ".debug_abbrev", @@ -826,33 +832,32 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { void MCObjectFileInfo::initWasmMCObjectFileInfo(const Triple &T) { // TODO: Set the section types and flags. - TextSection = Ctx->getWasmSection(".text", 0, 0); - DataSection = Ctx->getWasmSection(".data", 0, 0); + TextSection = Ctx->getWasmSection(".text", SectionKind::getText()); + DataSection = Ctx->getWasmSection(".data", SectionKind::getData()); // TODO: Set the section types and flags. - DwarfLineSection = Ctx->getWasmSection(".debug_line", 0, 0); - DwarfStrSection = Ctx->getWasmSection(".debug_str", 0, 0); - DwarfLocSection = Ctx->getWasmSection(".debug_loc", 0, 0); - DwarfAbbrevSection = Ctx->getWasmSection(".debug_abbrev", 0, 0, "section_abbrev"); - DwarfARangesSection = Ctx->getWasmSection(".debug_aranges", 0, 0); - DwarfRangesSection = Ctx->getWasmSection(".debug_ranges", 0, 0, "debug_range"); - DwarfMacinfoSection = Ctx->getWasmSection(".debug_macinfo", 0, 0, "debug_macinfo"); - DwarfAddrSection = Ctx->getWasmSection(".debug_addr", 0, 0); - DwarfCUIndexSection = Ctx->getWasmSection(".debug_cu_index", 0, 0); - DwarfTUIndexSection = Ctx->getWasmSection(".debug_tu_index", 0, 0); - DwarfInfoSection = Ctx->getWasmSection(".debug_info", 0, 0, "section_info"); - DwarfFrameSection = Ctx->getWasmSection(".debug_frame", 0, 0); - DwarfPubNamesSection = Ctx->getWasmSection(".debug_pubnames", 0, 0); - DwarfPubTypesSection = Ctx->getWasmSection(".debug_pubtypes", 0, 0); + DwarfLineSection = Ctx->getWasmSection(".debug_line", SectionKind::getMetadata()); + DwarfStrSection = Ctx->getWasmSection(".debug_str", SectionKind::getMetadata()); + DwarfLocSection = Ctx->getWasmSection(".debug_loc", SectionKind::getMetadata()); + DwarfAbbrevSection = Ctx->getWasmSection(".debug_abbrev", SectionKind::getMetadata(), "section_abbrev"); + DwarfARangesSection = Ctx->getWasmSection(".debug_aranges", SectionKind::getMetadata()); + DwarfRangesSection = Ctx->getWasmSection(".debug_ranges", SectionKind::getMetadata(), "debug_range"); + DwarfMacinfoSection = Ctx->getWasmSection(".debug_macinfo", SectionKind::getMetadata(), "debug_macinfo"); + DwarfAddrSection = Ctx->getWasmSection(".debug_addr", SectionKind::getMetadata()); + DwarfCUIndexSection = Ctx->getWasmSection(".debug_cu_index", SectionKind::getMetadata()); + DwarfTUIndexSection = Ctx->getWasmSection(".debug_tu_index", SectionKind::getMetadata()); + DwarfInfoSection = Ctx->getWasmSection(".debug_info", SectionKind::getMetadata(), "section_info"); + DwarfFrameSection = Ctx->getWasmSection(".debug_frame", SectionKind::getMetadata()); + DwarfPubNamesSection = Ctx->getWasmSection(".debug_pubnames", SectionKind::getMetadata()); + DwarfPubTypesSection = Ctx->getWasmSection(".debug_pubtypes", SectionKind::getMetadata()); // TODO: Define more sections. } void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, bool PIC, - CodeModel::Model cm, - MCContext &ctx) { + MCContext &ctx, + bool LargeCodeModel) { PositionIndependent = PIC; - CMModel = cm; Ctx = &ctx; // Common. @@ -890,7 +895,7 @@ void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, bool PIC, break; case Triple::ELF: Env = IsELF; - initELFMCObjectFileInfo(TT); + initELFMCObjectFileInfo(TT, LargeCodeModel); break; case Triple::Wasm: Env = IsWasm; diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index 174397e27396..15cc0faf5407 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -10,7 +10,6 @@ #include "llvm/MC/MCObjectStreamer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCAsmBackend.h" -#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCCodeView.h" @@ -22,23 +21,19 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SourceMgr.h" -#include "llvm/Support/TargetRegistry.h" using namespace llvm; -MCObjectStreamer::MCObjectStreamer(MCContext &Context, MCAsmBackend &TAB, +MCObjectStreamer::MCObjectStreamer(MCContext &Context, + std::unique_ptr<MCAsmBackend> TAB, raw_pwrite_stream &OS, - MCCodeEmitter *Emitter_) - : MCStreamer(Context), - Assembler(new MCAssembler(Context, TAB, *Emitter_, - *TAB.createObjectWriter(OS))), + std::unique_ptr<MCCodeEmitter> Emitter) + : MCStreamer(Context), ObjectWriter(TAB->createObjectWriter(OS)), + TAB(std::move(TAB)), Emitter(std::move(Emitter)), + Assembler(llvm::make_unique<MCAssembler>(Context, *this->TAB, + *this->Emitter, *ObjectWriter)), EmitEHFrame(true), EmitDebugFrame(false) {} -MCObjectStreamer::~MCObjectStreamer() { - delete &Assembler->getBackend(); - delete &Assembler->getEmitter(); - delete &Assembler->getWriter(); - delete Assembler; -} +MCObjectStreamer::~MCObjectStreamer() {} void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) { if (PendingLabels.empty()) @@ -111,6 +106,16 @@ MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() { return F; } +MCPaddingFragment *MCObjectStreamer::getOrCreatePaddingFragment() { + MCPaddingFragment *F = + dyn_cast_or_null<MCPaddingFragment>(getCurrentFragment()); + if (!F) { + F = new MCPaddingFragment(); + insert(F); + } + return F; +} + void MCObjectStreamer::visitUsedSymbol(const MCSymbol &Sym) { Assembler->registerSymbol(Sym); } @@ -147,6 +152,12 @@ void MCObjectStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, DF->getContents().resize(DF->getContents().size() + Size, 0); } +MCSymbol *MCObjectStreamer::EmitCFILabel() { + MCSymbol *Label = getContext().createTempSymbol("cfi", true); + EmitLabel(Label); + return Label; +} + void MCObjectStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) { // We need to create a local symbol to avoid relocations. Frame.Begin = getContext().createTempSymbol(); @@ -244,6 +255,13 @@ bool MCObjectStreamer::mayHaveInstructions(MCSection &Sec) const { void MCObjectStreamer::EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, bool) { + getAssembler().getBackend().handleCodePaddingInstructionBegin(Inst); + EmitInstructionImpl(Inst, STI); + getAssembler().getBackend().handleCodePaddingInstructionEnd(Inst); +} + +void MCObjectStreamer::EmitInstructionImpl(const MCInst &Inst, + const MCSubtargetInfo &STI) { MCStreamer::EmitInstruction(Inst, STI); MCSection *Sec = getCurrentSectionOnly(); @@ -426,6 +444,9 @@ void MCObjectStreamer::EmitCVFileChecksumsDirective() { getContext().getCVContext().emitFileChecksums(*this); } +void MCObjectStreamer::EmitCVFileChecksumOffsetDirective(unsigned FileNo) { + getContext().getCVContext().emitFileChecksumOffset(*this, FileNo); +} void MCObjectStreamer::EmitBytes(StringRef Data) { MCCVLineEntry::Make(this); @@ -461,6 +482,16 @@ void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset, insert(new MCOrgFragment(*Offset, Value, Loc)); } +void MCObjectStreamer::EmitCodePaddingBasicBlockStart( + const MCCodePaddingContext &Context) { + getAssembler().getBackend().handleCodePaddingBasicBlockStart(this, Context); +} + +void MCObjectStreamer::EmitCodePaddingBasicBlockEnd( + const MCCodePaddingContext &Context) { + getAssembler().getBackend().handleCodePaddingBasicBlockEnd(Context); +} + // Associate DTPRel32 fixup with data and resize data area void MCObjectStreamer::EmitDTPRel32Value(const MCExpr *Value) { MCDataFragment *DF = getOrCreateDataFragment(); diff --git a/lib/MC/MCParser/AsmLexer.cpp b/lib/MC/MCParser/AsmLexer.cpp index 2b963607b837..74835fd70c04 100644 --- a/lib/MC/MCParser/AsmLexer.cpp +++ b/lib/MC/MCParser/AsmLexer.cpp @@ -14,6 +14,7 @@ #include "llvm/MC/MCParser/AsmLexer.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/MC/MCAsmInfo.h" @@ -68,7 +69,7 @@ int AsmLexer::getNextChar() { /// consumed. AsmToken AsmLexer::LexFloatLiteral() { // Skip the fractional digit sequence. - while (isdigit(*CurPtr)) + while (isDigit(*CurPtr)) ++CurPtr; // Check for exponent; we intentionally accept a slighlty wider set of @@ -78,7 +79,7 @@ AsmToken AsmLexer::LexFloatLiteral() { ++CurPtr; if (*CurPtr == '-' || *CurPtr == '+') ++CurPtr; - while (isdigit(*CurPtr)) + while (isDigit(*CurPtr)) ++CurPtr; } @@ -102,7 +103,7 @@ AsmToken AsmLexer::LexHexFloatLiteral(bool NoIntDigits) { ++CurPtr; const char *FracStart = CurPtr; - while (isxdigit(*CurPtr)) + while (isHexDigit(*CurPtr)) ++CurPtr; NoFracDigits = CurPtr == FracStart; @@ -123,7 +124,7 @@ AsmToken AsmLexer::LexHexFloatLiteral(bool NoIntDigits) { // N.b. exponent digits are *not* hex const char *ExpStart = CurPtr; - while (isdigit(*CurPtr)) + while (isDigit(*CurPtr)) ++CurPtr; if (CurPtr == ExpStart) @@ -135,15 +136,15 @@ AsmToken AsmLexer::LexHexFloatLiteral(bool NoIntDigits) { /// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@?]* static bool IsIdentifierChar(char c, bool AllowAt) { - return isalnum(c) || c == '_' || c == '$' || c == '.' || + return isAlnum(c) || c == '_' || c == '$' || c == '.' || (c == '@' && AllowAt) || c == '?'; } AsmToken AsmLexer::LexIdentifier() { // Check for floating point literals. - if (CurPtr[-1] == '.' && isdigit(*CurPtr)) { + if (CurPtr[-1] == '.' && isDigit(*CurPtr)) { // Disambiguate a .1243foo identifier from a floating literal. - while (isdigit(*CurPtr)) + while (isDigit(*CurPtr)) ++CurPtr; if (*CurPtr == 'e' || *CurPtr == 'E' || !IsIdentifierChar(*CurPtr, AllowAtInIdentifier)) @@ -209,6 +210,8 @@ AsmToken AsmLexer::LexLineComment() { int CurChar = getNextChar(); while (CurChar != '\n' && CurChar != '\r' && CurChar != EOF) CurChar = getNextChar(); + if (CurChar == '\r' && CurPtr != CurBuf.end() && *CurPtr == '\n') + ++CurPtr; // If we have a CommentConsumer, notify it about the comment. if (CommentConsumer) { @@ -244,9 +247,9 @@ static unsigned doLookAhead(const char *&CurPtr, unsigned DefaultRadix) { const char *FirstHex = nullptr; const char *LookAhead = CurPtr; while (true) { - if (isdigit(*LookAhead)) { + if (isDigit(*LookAhead)) { ++LookAhead; - } else if (isxdigit(*LookAhead)) { + } else if (isHexDigit(*LookAhead)) { if (!FirstHex) FirstHex = LookAhead; ++LookAhead; @@ -282,7 +285,7 @@ AsmToken AsmLexer::LexDigit() { const char *FirstNonBinary = (CurPtr[-1] != '0' && CurPtr[-1] != '1') ? CurPtr - 1 : nullptr; const char *OldCurPtr = CurPtr; - while (isxdigit(*CurPtr)) { + while (isHexDigit(*CurPtr)) { if (*CurPtr != '0' && *CurPtr != '1' && !FirstNonBinary) FirstNonBinary = CurPtr; ++CurPtr; @@ -346,7 +349,7 @@ AsmToken AsmLexer::LexDigit() { if (!IsParsingMSInlineAsm && ((*CurPtr == 'b') || (*CurPtr == 'B'))) { ++CurPtr; // See if we actually have "0b" as part of something like "jmp 0b\n" - if (!isdigit(CurPtr[0])) { + if (!isDigit(CurPtr[0])) { --CurPtr; StringRef Result(TokStart, CurPtr - TokStart); return AsmToken(AsmToken::Integer, Result, 0); @@ -375,7 +378,7 @@ AsmToken AsmLexer::LexDigit() { if ((*CurPtr == 'x') || (*CurPtr == 'X')) { ++CurPtr; const char *NumStart = CurPtr; - while (isxdigit(CurPtr[0])) + while (isHexDigit(CurPtr[0])) ++CurPtr; // "0x.0p0" is valid, and "0x0p0" (but not "0xp0" for example, which will be @@ -605,8 +608,16 @@ AsmToken AsmLexer::LexToken() { return LexToken(); // Ignore whitespace. else return AsmToken(AsmToken::Space, StringRef(TokStart, CurPtr - TokStart)); + case '\r': { + IsAtStartOfLine = true; + IsAtStartOfStatement = true; + // If this is a CR followed by LF, treat that as one token. + if (CurPtr != CurBuf.end() && *CurPtr == '\n') + ++CurPtr; + return AsmToken(AsmToken::EndOfStatement, + StringRef(TokStart, CurPtr - TokStart)); + } case '\n': - case '\r': IsAtStartOfLine = true; IsAtStartOfStatement = true; return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index dad47e49e2c2..2259136c6ec4 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" @@ -387,37 +388,158 @@ private: // Generic (target and platform independent) directive parsing. enum DirectiveKind { DK_NO_DIRECTIVE, // Placeholder - DK_SET, DK_EQU, DK_EQUIV, DK_ASCII, DK_ASCIZ, DK_STRING, DK_BYTE, DK_SHORT, + DK_SET, + DK_EQU, + DK_EQUIV, + DK_ASCII, + DK_ASCIZ, + DK_STRING, + DK_BYTE, + DK_SHORT, DK_RELOC, - DK_VALUE, DK_2BYTE, DK_LONG, DK_INT, DK_4BYTE, DK_QUAD, DK_8BYTE, DK_OCTA, - DK_DC, DK_DC_A, DK_DC_B, DK_DC_D, DK_DC_L, DK_DC_S, DK_DC_W, DK_DC_X, - DK_DCB, DK_DCB_B, DK_DCB_D, DK_DCB_L, DK_DCB_S, DK_DCB_W, DK_DCB_X, - DK_DS, DK_DS_B, DK_DS_D, DK_DS_L, DK_DS_P, DK_DS_S, DK_DS_W, DK_DS_X, - DK_SINGLE, DK_FLOAT, DK_DOUBLE, DK_ALIGN, DK_ALIGN32, DK_BALIGN, DK_BALIGNW, - DK_BALIGNL, DK_P2ALIGN, DK_P2ALIGNW, DK_P2ALIGNL, DK_ORG, DK_FILL, DK_ENDR, - DK_BUNDLE_ALIGN_MODE, DK_BUNDLE_LOCK, DK_BUNDLE_UNLOCK, - DK_ZERO, DK_EXTERN, DK_GLOBL, DK_GLOBAL, - DK_LAZY_REFERENCE, DK_NO_DEAD_STRIP, DK_SYMBOL_RESOLVER, - DK_PRIVATE_EXTERN, DK_REFERENCE, DK_WEAK_DEFINITION, DK_WEAK_REFERENCE, - DK_WEAK_DEF_CAN_BE_HIDDEN, DK_COMM, DK_COMMON, DK_LCOMM, DK_ABORT, - DK_INCLUDE, DK_INCBIN, DK_CODE16, DK_CODE16GCC, DK_REPT, DK_IRP, DK_IRPC, - DK_IF, DK_IFEQ, DK_IFGE, DK_IFGT, DK_IFLE, DK_IFLT, DK_IFNE, DK_IFB, - DK_IFNB, DK_IFC, DK_IFEQS, DK_IFNC, DK_IFNES, DK_IFDEF, DK_IFNDEF, - DK_IFNOTDEF, DK_ELSEIF, DK_ELSE, DK_ENDIF, - DK_SPACE, DK_SKIP, DK_FILE, DK_LINE, DK_LOC, DK_STABS, - DK_CV_FILE, DK_CV_FUNC_ID, DK_CV_INLINE_SITE_ID, DK_CV_LOC, DK_CV_LINETABLE, - DK_CV_INLINE_LINETABLE, DK_CV_DEF_RANGE, DK_CV_STRINGTABLE, + DK_VALUE, + DK_2BYTE, + DK_LONG, + DK_INT, + DK_4BYTE, + DK_QUAD, + DK_8BYTE, + DK_OCTA, + DK_DC, + DK_DC_A, + DK_DC_B, + DK_DC_D, + DK_DC_L, + DK_DC_S, + DK_DC_W, + DK_DC_X, + DK_DCB, + DK_DCB_B, + DK_DCB_D, + DK_DCB_L, + DK_DCB_S, + DK_DCB_W, + DK_DCB_X, + DK_DS, + DK_DS_B, + DK_DS_D, + DK_DS_L, + DK_DS_P, + DK_DS_S, + DK_DS_W, + DK_DS_X, + DK_SINGLE, + DK_FLOAT, + DK_DOUBLE, + DK_ALIGN, + DK_ALIGN32, + DK_BALIGN, + DK_BALIGNW, + DK_BALIGNL, + DK_P2ALIGN, + DK_P2ALIGNW, + DK_P2ALIGNL, + DK_ORG, + DK_FILL, + DK_ENDR, + DK_BUNDLE_ALIGN_MODE, + DK_BUNDLE_LOCK, + DK_BUNDLE_UNLOCK, + DK_ZERO, + DK_EXTERN, + DK_GLOBL, + DK_GLOBAL, + DK_LAZY_REFERENCE, + DK_NO_DEAD_STRIP, + DK_SYMBOL_RESOLVER, + DK_PRIVATE_EXTERN, + DK_REFERENCE, + DK_WEAK_DEFINITION, + DK_WEAK_REFERENCE, + DK_WEAK_DEF_CAN_BE_HIDDEN, + DK_COMM, + DK_COMMON, + DK_LCOMM, + DK_ABORT, + DK_INCLUDE, + DK_INCBIN, + DK_CODE16, + DK_CODE16GCC, + DK_REPT, + DK_IRP, + DK_IRPC, + DK_IF, + DK_IFEQ, + DK_IFGE, + DK_IFGT, + DK_IFLE, + DK_IFLT, + DK_IFNE, + DK_IFB, + DK_IFNB, + DK_IFC, + DK_IFEQS, + DK_IFNC, + DK_IFNES, + DK_IFDEF, + DK_IFNDEF, + DK_IFNOTDEF, + DK_ELSEIF, + DK_ELSE, + DK_ENDIF, + DK_SPACE, + DK_SKIP, + DK_FILE, + DK_LINE, + DK_LOC, + DK_STABS, + DK_CV_FILE, + DK_CV_FUNC_ID, + DK_CV_INLINE_SITE_ID, + DK_CV_LOC, + DK_CV_LINETABLE, + DK_CV_INLINE_LINETABLE, + DK_CV_DEF_RANGE, + DK_CV_STRINGTABLE, DK_CV_FILECHECKSUMS, - DK_CFI_SECTIONS, DK_CFI_STARTPROC, DK_CFI_ENDPROC, DK_CFI_DEF_CFA, - DK_CFI_DEF_CFA_OFFSET, DK_CFI_ADJUST_CFA_OFFSET, DK_CFI_DEF_CFA_REGISTER, - DK_CFI_OFFSET, DK_CFI_REL_OFFSET, DK_CFI_PERSONALITY, DK_CFI_LSDA, - DK_CFI_REMEMBER_STATE, DK_CFI_RESTORE_STATE, DK_CFI_SAME_VALUE, - DK_CFI_RESTORE, DK_CFI_ESCAPE, DK_CFI_SIGNAL_FRAME, DK_CFI_UNDEFINED, - DK_CFI_REGISTER, DK_CFI_WINDOW_SAVE, - DK_MACROS_ON, DK_MACROS_OFF, DK_ALTMACRO, DK_NOALTMACRO, - DK_MACRO, DK_EXITM, DK_ENDM, DK_ENDMACRO, DK_PURGEM, - DK_SLEB128, DK_ULEB128, - DK_ERR, DK_ERROR, DK_WARNING, + DK_CV_FILECHECKSUM_OFFSET, + DK_CV_FPO_DATA, + DK_CFI_SECTIONS, + DK_CFI_STARTPROC, + DK_CFI_ENDPROC, + DK_CFI_DEF_CFA, + DK_CFI_DEF_CFA_OFFSET, + DK_CFI_ADJUST_CFA_OFFSET, + DK_CFI_DEF_CFA_REGISTER, + DK_CFI_OFFSET, + DK_CFI_REL_OFFSET, + DK_CFI_PERSONALITY, + DK_CFI_LSDA, + DK_CFI_REMEMBER_STATE, + DK_CFI_RESTORE_STATE, + DK_CFI_SAME_VALUE, + DK_CFI_RESTORE, + DK_CFI_ESCAPE, + DK_CFI_RETURN_COLUMN, + DK_CFI_SIGNAL_FRAME, + DK_CFI_UNDEFINED, + DK_CFI_REGISTER, + DK_CFI_WINDOW_SAVE, + DK_MACROS_ON, + DK_MACROS_OFF, + DK_ALTMACRO, + DK_NOALTMACRO, + DK_MACRO, + DK_EXITM, + DK_ENDM, + DK_ENDMACRO, + DK_PURGEM, + DK_SLEB128, + DK_ULEB128, + DK_ERR, + DK_ERROR, + DK_WARNING, + DK_PRINT, DK_END }; @@ -458,6 +580,8 @@ private: bool parseDirectiveCVDefRange(); bool parseDirectiveCVStringTable(); bool parseDirectiveCVFileChecksums(); + bool parseDirectiveCVFileChecksumOffset(); + bool parseDirectiveCVFPOData(); // .cfi directives bool parseDirectiveCFIRegister(SMLoc DirectiveLoc); @@ -477,6 +601,7 @@ private: bool parseDirectiveCFISameValue(SMLoc DirectiveLoc); bool parseDirectiveCFIRestore(SMLoc DirectiveLoc); bool parseDirectiveCFIEscape(); + bool parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc); bool parseDirectiveCFISignalFrame(); bool parseDirectiveCFIUndefined(SMLoc DirectiveLoc); @@ -560,6 +685,9 @@ private: // ".warning" bool parseDirectiveWarning(SMLoc DirectiveLoc); + // .print <double-quotes-string> + bool parseDirectivePrint(SMLoc DirectiveLoc); + void initializeDirectiveKindMap(); }; @@ -1208,10 +1336,10 @@ bool AsmParser::isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc) { assert((StrLoc.getPointer() != NULL) && "Argument to the function cannot be a NULL value"); const char *CharPtr = StrLoc.getPointer(); - while ((*CharPtr != '>') && (*CharPtr != '\n') && - (*CharPtr != '\r') && (*CharPtr != '\0')){ - if(*CharPtr == '!') - CharPtr++; + while ((*CharPtr != '>') && (*CharPtr != '\n') && (*CharPtr != '\r') && + (*CharPtr != '\0')) { + if (*CharPtr == '!') + CharPtr++; CharPtr++; } if (*CharPtr == '>') { @@ -1529,16 +1657,6 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, Lex(); return false; } - if (Lexer.is(AsmToken::Hash)) { - // Seeing a hash here means that it was an end-of-line comment in - // an asm syntax where hash's are not comment and the previous - // statement parser did not check the end of statement. Relex as - // EndOfStatement. - StringRef CommentStr = parseStringToEndOfStatement(); - Lexer.Lex(); - Lexer.UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr)); - return false; - } // Statements always start with an identifier. AsmToken ID = getTok(); SMLoc IDLoc = ID.getLoc(); @@ -1578,6 +1696,11 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, // Treat '}' as a valid identifier in this context. Lex(); IDVal = "}"; + } else if (Lexer.is(AsmToken::Star) && + getTargetParser().starIsStartOfStatement()) { + // Accept '*' as a valid start of statement. + Lex(); + IDVal = "*"; } else if (parseIdentifier(IDVal)) { if (!TheCondState.Ignore) { Lex(); // always eat a token @@ -1916,6 +2039,10 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, return parseDirectiveCVStringTable(); case DK_CV_FILECHECKSUMS: return parseDirectiveCVFileChecksums(); + case DK_CV_FILECHECKSUM_OFFSET: + return parseDirectiveCVFileChecksumOffset(); + case DK_CV_FPO_DATA: + return parseDirectiveCVFPOData(); case DK_CFI_SECTIONS: return parseDirectiveCFISections(); case DK_CFI_STARTPROC: @@ -1948,6 +2075,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, return parseDirectiveCFIRestore(IDLoc); case DK_CFI_ESCAPE: return parseDirectiveCFIEscape(); + case DK_CFI_RETURN_COLUMN: + return parseDirectiveCFIReturnColumn(IDLoc); case DK_CFI_SIGNAL_FRAME: return parseDirectiveCFISignalFrame(); case DK_CFI_UNDEFINED: @@ -2009,6 +2138,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, case DK_DS_P: case DK_DS_X: return parseDirectiveDS(IDVal, 12); + case DK_PRINT: + return parseDirectivePrint(IDLoc); } return Error(IDLoc, "unknown directive"); @@ -3078,7 +3209,7 @@ bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) { int64_t MaxBytesToFill = 0; auto parseAlign = [&]() -> bool { - if (checkForValidSection() || parseAbsoluteExpression(Alignment)) + if (parseAbsoluteExpression(Alignment)) return true; if (parseOptionalToken(AsmToken::Comma)) { // The fill expression can be omitted while specifying a maximum number of @@ -3097,6 +3228,13 @@ bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) { return parseToken(AsmToken::EndOfStatement); }; + if (checkForValidSection()) + return addErrorSuffix(" in directive"); + // Ignore empty '.p2align' directives for GNU-as compatibility + if (IsPow2 && (ValueSize == 1) && getTok().is(AsmToken::EndOfStatement)) { + Warning(AlignmentLoc, "p2align directive with no operand(s) is ignored"); + return parseToken(AsmToken::EndOfStatement); + } if (parseAlign()) return addErrorSuffix(" in directive"); @@ -3334,25 +3472,40 @@ bool AsmParser::parseDirectiveStabs() { } /// parseDirectiveCVFile -/// ::= .cv_file number filename +/// ::= .cv_file number filename [checksum] [checksumkind] bool AsmParser::parseDirectiveCVFile() { SMLoc FileNumberLoc = getTok().getLoc(); int64_t FileNumber; std::string Filename; + std::string Checksum; + int64_t ChecksumKind = 0; if (parseIntToken(FileNumber, "expected file number in '.cv_file' directive") || check(FileNumber < 1, FileNumberLoc, "file number less than one") || check(getTok().isNot(AsmToken::String), "unexpected token in '.cv_file' directive") || - // Usually directory and filename are together, otherwise just - // directory. Allow the strings to have escaped octal character sequence. - parseEscapedString(Filename) || - parseToken(AsmToken::EndOfStatement, - "unexpected token in '.cv_file' directive")) + parseEscapedString(Filename)) return true; + if (!parseOptionalToken(AsmToken::EndOfStatement)) { + if (check(getTok().isNot(AsmToken::String), + "unexpected token in '.cv_file' directive") || + parseEscapedString(Checksum) || + parseIntToken(ChecksumKind, + "expected checksum kind in '.cv_file' directive") || + parseToken(AsmToken::EndOfStatement, + "unexpected token in '.cv_file' directive")) + return true; + } - if (!getStreamer().EmitCVFileDirective(FileNumber, Filename)) + Checksum = fromHex(Checksum); + void *CKMem = Ctx.allocate(Checksum.size(), 1); + memcpy(CKMem, Checksum.data(), Checksum.size()); + ArrayRef<uint8_t> ChecksumAsBytes(reinterpret_cast<const uint8_t *>(CKMem), + Checksum.size()); + + if (!getStreamer().EmitCVFileDirective(FileNumber, Filename, ChecksumAsBytes, + static_cast<uint8_t>(ChecksumKind))) return Error(FileNumberLoc, "file number already allocated"); return false; @@ -3468,7 +3621,6 @@ bool AsmParser::parseDirectiveCVInlineSiteId() { /// optional items are .loc sub-directives. bool AsmParser::parseDirectiveCVLoc() { SMLoc DirectiveLoc = getTok().getLoc(); - SMLoc Loc; int64_t FunctionId, FileNumber; if (parseCVFunctionId(FunctionId, ".cv_loc") || parseCVFileId(FileNumber, ".cv_loc")) @@ -3631,6 +3783,32 @@ bool AsmParser::parseDirectiveCVFileChecksums() { return false; } +/// parseDirectiveCVFileChecksumOffset +/// ::= .cv_filechecksumoffset fileno +bool AsmParser::parseDirectiveCVFileChecksumOffset() { + int64_t FileNo; + if (parseIntToken(FileNo, "expected identifier in directive")) + return true; + if (parseToken(AsmToken::EndOfStatement, "Expected End of Statement")) + return true; + getStreamer().EmitCVFileChecksumOffsetDirective(FileNo); + return false; +} + +/// parseDirectiveCVFPOData +/// ::= .cv_fpo_data procsym +bool AsmParser::parseDirectiveCVFPOData() { + SMLoc DirLoc = getLexer().getLoc(); + StringRef ProcName; + if (parseIdentifier(ProcName)) + return TokError("expected symbol name"); + if (parseEOL("unexpected tokens")) + return addErrorSuffix(" in '.cv_fpo_data' directive"); + MCSymbol *ProcSym = getContext().getOrCreateSymbol(ProcName); + getStreamer().EmitCVFPOData(ProcSym, DirLoc); + return false; +} + /// parseDirectiveCFISections /// ::= .cfi_sections section [, section] bool AsmParser::parseDirectiveCFISections() { @@ -3902,6 +4080,16 @@ bool AsmParser::parseDirectiveCFIEscape() { return false; } +/// parseDirectiveCFIReturnColumn +/// ::= .cfi_return_column register +bool AsmParser::parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc) { + int64_t Register = 0; + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + getStreamer().EmitCFIReturnColumn(Register); + return false; +} + /// parseDirectiveCFISignalFrame /// ::= .cfi_signal_frame bool AsmParser::parseDirectiveCFISignalFrame() { @@ -5003,6 +5191,8 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE; DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE; DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS; + DirectiveKindMap[".cv_filechecksumoffset"] = DK_CV_FILECHECKSUM_OFFSET; + DirectiveKindMap[".cv_fpo_data"] = DK_CV_FPO_DATA; DirectiveKindMap[".sleb128"] = DK_SLEB128; DirectiveKindMap[".uleb128"] = DK_ULEB128; DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS; @@ -5021,6 +5211,7 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".cfi_same_value"] = DK_CFI_SAME_VALUE; DirectiveKindMap[".cfi_restore"] = DK_CFI_RESTORE; DirectiveKindMap[".cfi_escape"] = DK_CFI_ESCAPE; + DirectiveKindMap[".cfi_return_column"] = DK_CFI_RETURN_COLUMN; DirectiveKindMap[".cfi_signal_frame"] = DK_CFI_SIGNAL_FRAME; DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED; DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER; @@ -5061,6 +5252,7 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".ds.s"] = DK_DS_S; DirectiveKindMap[".ds.w"] = DK_DS_W; DirectiveKindMap[".ds.x"] = DK_DS_X; + DirectiveKindMap[".print"] = DK_PRINT; } MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { @@ -5289,6 +5481,17 @@ bool AsmParser::parseDirectiveMSAlign(SMLoc IDLoc, ParseStatementInfo &Info) { return false; } +bool AsmParser::parseDirectivePrint(SMLoc DirectiveLoc) { + const AsmToken StrTok = getTok(); + Lex(); + if (StrTok.isNot(AsmToken::String) || StrTok.getString().front() != '"') + return Error(DirectiveLoc, "expected double quoted string after .print"); + if (parseToken(AsmToken::EndOfStatement, "expected end of statement")) + return true; + llvm::outs() << StrTok.getStringContents() << '\n'; + return false; +} + // We are comparing pointers, but the pointers are relative to a single string. // Thus, this should always be deterministic. static int rewritesSort(const AsmRewrite *AsmRewriteA, @@ -5444,8 +5647,6 @@ bool AsmParser::parseMSInlineAsm( array_pod_sort(AsmStrRewrites.begin(), AsmStrRewrites.end(), rewritesSort); for (const AsmRewrite &AR : AsmStrRewrites) { AsmRewriteKind Kind = AR.Kind; - if (Kind == AOK_Delete) - continue; const char *Loc = AR.Loc.getPointer(); assert(Loc >= AsmStart && "Expected Loc to be at or after Start!"); @@ -5465,11 +5666,21 @@ bool AsmParser::parseMSInlineAsm( switch (Kind) { default: break; - case AOK_Imm: - OS << "$$" << AR.Val; - break; - case AOK_ImmPrefix: - OS << "$$"; + case AOK_IntelExpr: + assert(AR.IntelExp.isValid() && "cannot write invalid intel expression"); + if (AR.IntelExp.NeedBracs) + OS << "["; + if (AR.IntelExp.hasBaseReg()) + OS << AR.IntelExp.BaseReg; + if (AR.IntelExp.hasIndexReg()) + OS << (AR.IntelExp.hasBaseReg() ? " + " : "") + << AR.IntelExp.IndexReg; + if (AR.IntelExp.Scale > 1) + OS << " * $$" << AR.IntelExp.Scale; + if (AR.IntelExp.Imm || !AR.IntelExp.hasRegs()) + OS << (AR.IntelExp.hasRegs() ? " + $$" : "$$") << AR.IntelExp.Imm; + if (AR.IntelExp.NeedBracs) + OS << "]"; break; case AOK_Label: OS << Ctx.getAsmInfo()->getPrivateLabelPrefix() << AR.Label; @@ -5513,13 +5724,6 @@ bool AsmParser::parseMSInlineAsm( case AOK_EVEN: OS << ".even"; break; - case AOK_DotOperator: - // Insert the dot if the user omitted it. - OS.flush(); - if (AsmStringIR.back() != '.') - OS << '.'; - OS << AR.Val; - break; case AOK_EndOfStatement: OS << "\n\t"; break; diff --git a/lib/MC/MCParser/COFFAsmParser.cpp b/lib/MC/MCParser/COFFAsmParser.cpp index b83d68d4fe20..687e0cc1faa5 100644 --- a/lib/MC/MCParser/COFFAsmParser.cpp +++ b/lib/MC/MCParser/COFFAsmParser.cpp @@ -568,7 +568,7 @@ bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) { return false; } -bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) { +bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) { StringRef SymbolID; if (getParser().parseIdentifier(SymbolID)) return true; @@ -579,29 +579,29 @@ bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) { MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); Lex(); - getStreamer().EmitWinCFIStartProc(Symbol); + getStreamer().EmitWinCFIStartProc(Symbol, Loc); return false; } -bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) { +bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) { Lex(); - getStreamer().EmitWinCFIEndProc(); + getStreamer().EmitWinCFIEndProc(Loc); return false; } -bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) { +bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) { Lex(); - getStreamer().EmitWinCFIStartChained(); + getStreamer().EmitWinCFIStartChained(Loc); return false; } -bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) { +bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) { Lex(); - getStreamer().EmitWinCFIEndChained(); + getStreamer().EmitWinCFIEndChained(Loc); return false; } -bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) { +bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) { StringRef SymbolID; if (getParser().parseIdentifier(SymbolID)) return true; @@ -623,17 +623,17 @@ bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) { MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID); Lex(); - getStreamer().EmitWinEHHandler(handler, unwind, except); + getStreamer().EmitWinEHHandler(handler, unwind, except, Loc); return false; } -bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) { +bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) { Lex(); getStreamer().EmitWinEHHandlerData(); return false; } -bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) { +bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc Loc) { unsigned Reg = 0; if (ParseSEHRegisterNumber(Reg)) return true; @@ -642,11 +642,11 @@ bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) { return TokError("unexpected token in directive"); Lex(); - getStreamer().EmitWinCFIPushReg(Reg); + getStreamer().EmitWinCFIPushReg(Reg, Loc); return false; } -bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) { +bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc Loc) { unsigned Reg = 0; int64_t Off; if (ParseSEHRegisterNumber(Reg)) @@ -655,39 +655,31 @@ bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) { return TokError("you must specify a stack pointer offset"); Lex(); - SMLoc startLoc = getLexer().getLoc(); if (getParser().parseAbsoluteExpression(Off)) return true; - if (Off & 0x0F) - return Error(startLoc, "offset is not a multiple of 16"); - if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in directive"); Lex(); - getStreamer().EmitWinCFISetFrame(Reg, Off); + getStreamer().EmitWinCFISetFrame(Reg, Off, Loc); return false; } -bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) { +bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) { int64_t Size; - SMLoc startLoc = getLexer().getLoc(); if (getParser().parseAbsoluteExpression(Size)) return true; - if (Size & 7) - return Error(startLoc, "size is not a multiple of 8"); - if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in directive"); Lex(); - getStreamer().EmitWinCFIAllocStack(Size); + getStreamer().EmitWinCFIAllocStack(Size, Loc); return false; } -bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) { +bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc Loc) { unsigned Reg = 0; int64_t Off; if (ParseSEHRegisterNumber(Reg)) @@ -696,25 +688,21 @@ bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) { return TokError("you must specify an offset on the stack"); Lex(); - SMLoc startLoc = getLexer().getLoc(); if (getParser().parseAbsoluteExpression(Off)) return true; - if (Off & 7) - return Error(startLoc, "size is not a multiple of 8"); - if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in directive"); Lex(); // FIXME: Err on %xmm* registers - getStreamer().EmitWinCFISaveReg(Reg, Off); + getStreamer().EmitWinCFISaveReg(Reg, Off, Loc); return false; } // FIXME: This method is inherently x86-specific. It should really be in the // x86 backend. -bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) { +bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc Loc) { unsigned Reg = 0; int64_t Off; if (ParseSEHRegisterNumber(Reg)) @@ -723,23 +711,19 @@ bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) { return TokError("you must specify an offset on the stack"); Lex(); - SMLoc startLoc = getLexer().getLoc(); if (getParser().parseAbsoluteExpression(Off)) return true; if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in directive"); - if (Off & 0x0F) - return Error(startLoc, "offset is not a multiple of 16"); - Lex(); // FIXME: Err on non-%xmm* registers - getStreamer().EmitWinCFISaveXMM(Reg, Off); + getStreamer().EmitWinCFISaveXMM(Reg, Off, Loc); return false; } -bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) { +bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc Loc) { bool Code = false; StringRef CodeID; if (getLexer().is(AsmToken::At)) { @@ -756,13 +740,13 @@ bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) { return TokError("unexpected token in directive"); Lex(); - getStreamer().EmitWinCFIPushFrame(Code); + getStreamer().EmitWinCFIPushFrame(Code, Loc); return false; } -bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) { +bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) { Lex(); - getStreamer().EmitWinCFIEndProlog(); + getStreamer().EmitWinCFIEndProlog(Loc); return false; } diff --git a/lib/MC/MCParser/DarwinAsmParser.cpp b/lib/MC/MCParser/DarwinAsmParser.cpp index f4152a9067a0..195ddc78d454 100644 --- a/lib/MC/MCParser/DarwinAsmParser.cpp +++ b/lib/MC/MCParser/DarwinAsmParser.cpp @@ -54,7 +54,7 @@ class DarwinAsmParser : public MCAsmParserExtension { unsigned TAA = 0, unsigned ImplicitAlign = 0, unsigned StubSize = 0); - SMLoc LastVersionMinDirective; + SMLoc LastVersionDirective; public: DarwinAsmParser() = default; @@ -186,14 +186,17 @@ public: addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveTLV>(".tlv"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveIdent>(".ident"); - addDirectiveHandler<&DarwinAsmParser::parseVersionMin>( + addDirectiveHandler<&DarwinAsmParser::parseWatchOSVersionMin>( ".watchos_version_min"); - addDirectiveHandler<&DarwinAsmParser::parseVersionMin>(".tvos_version_min"); - addDirectiveHandler<&DarwinAsmParser::parseVersionMin>(".ios_version_min"); - addDirectiveHandler<&DarwinAsmParser::parseVersionMin>( + addDirectiveHandler<&DarwinAsmParser::parseTvOSVersionMin>( + ".tvos_version_min"); + addDirectiveHandler<&DarwinAsmParser::parseIOSVersionMin>( + ".ios_version_min"); + addDirectiveHandler<&DarwinAsmParser::parseMacOSXVersionMin>( ".macosx_version_min"); + addDirectiveHandler<&DarwinAsmParser::parseBuildVersion>(".build_version"); - LastVersionMinDirective = SMLoc(); + LastVersionDirective = SMLoc(); } bool parseDirectiveAltEntry(StringRef, SMLoc); @@ -441,7 +444,24 @@ public: MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS); } - bool parseVersionMin(StringRef, SMLoc); + bool parseWatchOSVersionMin(StringRef Directive, SMLoc Loc) { + return parseVersionMin(Directive, Loc, MCVM_WatchOSVersionMin); + } + bool parseTvOSVersionMin(StringRef Directive, SMLoc Loc) { + return parseVersionMin(Directive, Loc, MCVM_TvOSVersionMin); + } + bool parseIOSVersionMin(StringRef Directive, SMLoc Loc) { + return parseVersionMin(Directive, Loc, MCVM_IOSVersionMin); + } + bool parseMacOSXVersionMin(StringRef Directive, SMLoc Loc) { + return parseVersionMin(Directive, Loc, MCVM_OSXVersionMin); + } + + bool parseBuildVersion(StringRef Directive, SMLoc Loc); + bool parseVersionMin(StringRef Directive, SMLoc Loc, MCVersionMinType Type); + bool parseVersion(unsigned *Major, unsigned *Minor, unsigned *Update); + void checkVersion(StringRef Directive, StringRef Arg, SMLoc Loc, + Triple::OSType ExpectedOS); }; } // end anonymous namespace @@ -978,70 +998,144 @@ bool DarwinAsmParser::parseDirectiveDataRegionEnd(StringRef, SMLoc) { return false; } -/// parseVersionMin -/// ::= .ios_version_min major,minor[,update] -/// ::= .macosx_version_min major,minor[,update] -bool DarwinAsmParser::parseVersionMin(StringRef Directive, SMLoc Loc) { - int64_t Major = 0, Minor = 0, Update = 0; - int Kind = StringSwitch<int>(Directive) - .Case(".watchos_version_min", MCVM_WatchOSVersionMin) - .Case(".tvos_version_min", MCVM_TvOSVersionMin) - .Case(".ios_version_min", MCVM_IOSVersionMin) - .Case(".macosx_version_min", MCVM_OSXVersionMin); +/// parseVersion ::= major, minor [, update] +bool DarwinAsmParser::parseVersion(unsigned *Major, unsigned *Minor, + unsigned *Update) { // Get the major version number. if (getLexer().isNot(AsmToken::Integer)) + return TokError("invalid OS major version number, integer expected"); + int64_t MajorVal = getLexer().getTok().getIntVal(); + if (MajorVal > 65535 || MajorVal <= 0) return TokError("invalid OS major version number"); - Major = getLexer().getTok().getIntVal(); - if (Major > 65535 || Major <= 0) - return TokError("invalid OS major version number"); + *Major = (unsigned)MajorVal; Lex(); if (getLexer().isNot(AsmToken::Comma)) - return TokError("minor OS version number required, comma expected"); + return TokError("OS 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"); + int64_t MinorVal = getLexer().getTok().getIntVal(); + if (MinorVal > 255 || MinorVal < 0) return TokError("invalid OS minor version number"); - Minor = getLexer().getTok().getIntVal(); - if (Minor > 255 || Minor < 0) - return TokError("invalid OS minor version number"); + *Minor = MinorVal; Lex(); + // Get the update level, if specified - if (getLexer().isNot(AsmToken::EndOfStatement)) { - if (getLexer().isNot(AsmToken::Comma)) - return TokError("invalid update specifier, comma expected"); - Lex(); - if (getLexer().isNot(AsmToken::Integer)) - return TokError("invalid OS update number"); - Update = getLexer().getTok().getIntVal(); - if (Update > 255 || Update < 0) - return TokError("invalid OS update number"); - Lex(); + *Update = 0; + if (getLexer().is(AsmToken::EndOfStatement)) + return false; + if (getLexer().isNot(AsmToken::Comma)) + return TokError("invalid OS update specifier, comma expected"); + 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(); + return false; +} + +void DarwinAsmParser::checkVersion(StringRef Directive, StringRef Arg, + SMLoc Loc, Triple::OSType ExpectedOS) { + const Triple &Target = getContext().getObjectFileInfo()->getTargetTriple(); + if (Target.getOS() != ExpectedOS) + Warning(Loc, Twine(Directive) + + (Arg.empty() ? Twine() : Twine(' ') + Arg) + + " used while targeting " + Target.getOSName()); + + if (LastVersionDirective.isValid()) { + Warning(Loc, "overriding previous version directive"); + Note(LastVersionDirective, "previous definition is here"); } + LastVersionDirective = Loc; +} - const Triple &T = getContext().getObjectFileInfo()->getTargetTriple(); - Triple::OSType ExpectedOS = Triple::UnknownOS; - switch ((MCVersionMinType)Kind) { - case MCVM_WatchOSVersionMin: ExpectedOS = Triple::WatchOS; break; - case MCVM_TvOSVersionMin: ExpectedOS = Triple::TvOS; break; - case MCVM_IOSVersionMin: ExpectedOS = Triple::IOS; break; - case MCVM_OSXVersionMin: ExpectedOS = Triple::MacOSX; break; +static Triple::OSType getOSTypeFromMCVM(MCVersionMinType Type) { + switch (Type) { + case MCVM_WatchOSVersionMin: return Triple::WatchOS; + case MCVM_TvOSVersionMin: return Triple::TvOS; + case MCVM_IOSVersionMin: return Triple::IOS; + case MCVM_OSXVersionMin: return Triple::MacOSX; } - if (T.getOS() != ExpectedOS) - Warning(Loc, Directive + " should only be used for " + - Triple::getOSTypeName(ExpectedOS) + " targets"); + llvm_unreachable("Invalid mc version min type"); +} + +/// parseVersionMin +/// ::= .ios_version_min parseVersion +/// | .macosx_version_min parseVersion +/// | .tvos_version_min parseVersion +/// | .watchos_version_min parseVersion +bool DarwinAsmParser::parseVersionMin(StringRef Directive, SMLoc Loc, + MCVersionMinType Type) { + unsigned Major; + unsigned Minor; + unsigned Update; + if (parseVersion(&Major, &Minor, &Update)) + 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); + return false; +} - if (LastVersionMinDirective.isValid()) { - Warning(Loc, "overriding previous version_min directive"); - Note(LastVersionMinDirective, "previous definition is here"); +Triple::OSType getOSTypeFromPlatform(MachO::PlatformType Type) { + switch (Type) { + case MachO::PLATFORM_MACOS: return Triple::MacOSX; + 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; } - LastVersionMinDirective = Loc; + llvm_unreachable("Invalid mach-o platform type"); +} - // We've parsed a correct version specifier, so send it to the streamer. - getStreamer().EmitVersionMin((MCVersionMinType)Kind, Major, Minor, Update); +/// parseBuildVersion +/// ::= .build_version (macos|ios|tvos|watchos), parseVersion +bool DarwinAsmParser::parseBuildVersion(StringRef Directive, SMLoc Loc) { + StringRef PlatformName; + SMLoc PlatformLoc = getTok().getLoc(); + if (getParser().parseIdentifier(PlatformName)) + return TokError("platform name expected"); + + unsigned Platform = StringSwitch<unsigned>(PlatformName) + .Case("macos", MachO::PLATFORM_MACOS) + .Case("ios", MachO::PLATFORM_IOS) + .Case("tvos", MachO::PLATFORM_TVOS) + .Case("watchos", MachO::PLATFORM_WATCHOS) + .Default(0); + if (Platform == 0) + return Error(PlatformLoc, "unknown platform name"); + if (getLexer().isNot(AsmToken::Comma)) + return TokError("version number required, comma expected"); + Lex(); + + unsigned Major; + unsigned Minor; + unsigned Update; + if (parseVersion(&Major, &Minor, &Update)) + 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); return false; } + namespace llvm { MCAsmParserExtension *createDarwinAsmParser() { diff --git a/lib/MC/MCParser/ELFAsmParser.cpp b/lib/MC/MCParser/ELFAsmParser.cpp index a407691b0bd1..38720c23ff26 100644 --- a/lib/MC/MCParser/ELFAsmParser.cpp +++ b/lib/MC/MCParser/ELFAsmParser.cpp @@ -247,7 +247,7 @@ bool ELFAsmParser::ParseSectionName(StringRef &SectionName) { return false; } - while (true) { + while (!getParser().hasPendingError()) { SMLoc PrevLoc = getLexer().getLoc(); if (getLexer().is(AsmToken::Comma) || getLexer().is(AsmToken::EndOfStatement)) @@ -488,7 +488,6 @@ bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) { unsigned Flags = 0; const MCExpr *Subsection = nullptr; bool UseLastGroup = false; - StringRef UniqueStr; MCSymbolELF *Associated = nullptr; int64_t UniqueID = ~0; diff --git a/lib/MC/MCParser/MCAsmParser.cpp b/lib/MC/MCParser/MCAsmParser.cpp index ea36b3b9b3b2..6a4c74cd57fe 100644 --- a/lib/MC/MCParser/MCAsmParser.cpp +++ b/lib/MC/MCParser/MCAsmParser.cpp @@ -40,11 +40,6 @@ bool MCAsmParser::parseTokenLoc(SMLoc &Loc) { } bool MCAsmParser::parseEOL(const Twine &Msg) { - if (getTok().getKind() == AsmToken::Hash) { - StringRef CommentStr = parseStringToEndOfStatement(); - getLexer().Lex(); - getLexer().UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr)); - } if (getTok().getKind() != AsmToken::EndOfStatement) return Error(getTok().getLoc(), Msg); Lex(); @@ -70,9 +65,6 @@ bool MCAsmParser::parseIntToken(int64_t &V, const Twine &Msg) { bool MCAsmParser::parseOptionalToken(AsmToken::TokenKind T) { bool Present = (getTok().getKind() == T); - // if token is EOL and current token is # this is an EOL comment. - if (getTok().getKind() == AsmToken::Hash && T == AsmToken::EndOfStatement) - Present = true; if (Present) parseToken(T); return Present; diff --git a/lib/MC/MCParser/MCTargetAsmParser.cpp b/lib/MC/MCParser/MCTargetAsmParser.cpp index 64ac82a6c66f..a0c06c9d5018 100644 --- a/lib/MC/MCParser/MCTargetAsmParser.cpp +++ b/lib/MC/MCParser/MCTargetAsmParser.cpp @@ -13,8 +13,9 @@ using namespace llvm; MCTargetAsmParser::MCTargetAsmParser(MCTargetOptions const &MCOptions, - const MCSubtargetInfo &STI) - : MCOptions(MCOptions), STI(&STI) {} + const MCSubtargetInfo &STI, + const MCInstrInfo &MII) + : MCOptions(MCOptions), STI(&STI), MII(MII) {} MCTargetAsmParser::~MCTargetAsmParser() = default; diff --git a/lib/MC/MCRegisterInfo.cpp b/lib/MC/MCRegisterInfo.cpp index 0f76c1838b51..8e47963b4418 100644 --- a/lib/MC/MCRegisterInfo.cpp +++ b/lib/MC/MCRegisterInfo.cpp @@ -88,6 +88,34 @@ int MCRegisterInfo::getLLVMRegNum(unsigned RegNum, bool isEH) const { return I->ToReg; } +int MCRegisterInfo::getLLVMRegNumFromEH(unsigned RegNum) const { + const DwarfLLVMRegPair *M = EHDwarf2LRegs; + unsigned Size = EHDwarf2LRegsSize; + + if (!M) + return -1; + DwarfLLVMRegPair Key = { RegNum, 0 }; + const DwarfLLVMRegPair *I = std::lower_bound(M, M+Size, Key); + if (I == M+Size || I->FromReg != RegNum) + return -1; + return I->ToReg; +} + +int MCRegisterInfo::getDwarfRegNumFromDwarfEHRegNum(unsigned RegNum) const { + // On ELF platforms, DWARF EH register numbers are the same as DWARF + // other register numbers. On Darwin x86, they differ and so need to be + // mapped. The .cfi_* directives accept integer literals as well as + // register names and should generate exactly what the assembly code + // asked for, so there might be DWARF/EH register numbers that don't have + // a corresponding LLVM register number at all. So if we can't map the + // EH register number to an LLVM register number, assume it's just a + // valid DWARF register number as is. + int LRegNum = getLLVMRegNumFromEH(RegNum); + if (LRegNum != -1) + return getDwarfRegNum(LRegNum, false); + return RegNum; +} + int MCRegisterInfo::getSEHRegNum(unsigned RegNum) const { const DenseMap<unsigned, int>::const_iterator I = L2SEHRegs.find(RegNum); if (I == L2SEHRegs.end()) return (int)RegNum; diff --git a/lib/MC/MCSectionELF.cpp b/lib/MC/MCSectionELF.cpp index 2f4f61aa4d50..bf1fcb03273c 100644 --- a/lib/MC/MCSectionELF.cpp +++ b/lib/MC/MCSectionELF.cpp @@ -113,8 +113,7 @@ void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, OS << 'c'; if (Flags & ELF::XCORE_SHF_DP_SECTION) OS << 'd'; - } else if (Arch == Triple::arm || Arch == Triple::armeb || - Arch == Triple::thumb || Arch == Triple::thumbeb) { + } else if (T.isARM() || T.isThumb()) { if (Flags & ELF::SHF_ARM_PURECODE) OS << 'y'; } diff --git a/lib/MC/MCSectionWasm.cpp b/lib/MC/MCSectionWasm.cpp index c61f28e129f5..626027a24f97 100644 --- a/lib/MC/MCSectionWasm.cpp +++ b/lib/MC/MCSectionWasm.cpp @@ -9,7 +9,6 @@ #include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp index 2bfb9a63eedb..6f3647d61932 100644 --- a/lib/MC/MCStreamer.cpp +++ b/lib/MC/MCStreamer.cpp @@ -56,17 +56,12 @@ MCStreamer::MCStreamer(MCContext &Ctx) SectionStack.push_back(std::pair<MCSectionSubPair, MCSectionSubPair>()); } -MCStreamer::~MCStreamer() { - for (unsigned i = 0; i < getNumWinFrameInfos(); ++i) - delete WinFrameInfos[i]; -} +MCStreamer::~MCStreamer() {} void MCStreamer::reset() { DwarfFrameInfos.clear(); - for (unsigned i = 0; i < getNumWinFrameInfos(); ++i) - delete WinFrameInfos[i]; - WinFrameInfos.clear(); CurrentWinFrameInfo = nullptr; + WinFrameInfos.clear(); SymbolOrdering.clear(); SectionStack.clear(); SectionStack.push_back(std::pair<MCSectionSubPair, MCSectionSubPair>()); @@ -105,13 +100,17 @@ void MCStreamer::EmitIntValue(uint64_t Value, unsigned Size) { /// EmitULEB128Value - Special case of EmitULEB128Value that avoids the /// client having to pass in a MCExpr for constant integers. -void MCStreamer::EmitULEB128IntValue(uint64_t Value, unsigned Padding) { +void MCStreamer::EmitPaddedULEB128IntValue(uint64_t Value, unsigned PadTo) { SmallString<128> Tmp; raw_svector_ostream OSE(Tmp); - encodeULEB128(Value, OSE, Padding); + encodeULEB128(Value, OSE, PadTo); EmitBytes(OSE.str()); } +void MCStreamer::EmitULEB128IntValue(uint64_t Value) { + EmitPaddedULEB128IntValue(Value, 0); +} + /// EmitSLEB128Value - Special case of EmitSLEB128Value that avoids the /// client having to pass in a MCExpr for constant integers. void MCStreamer::EmitSLEB128IntValue(int64_t Value) { @@ -207,25 +206,25 @@ MCSymbol *MCStreamer::getDwarfLineTableSymbol(unsigned CUID) { return Table.getLabel(); } -MCDwarfFrameInfo *MCStreamer::getCurrentDwarfFrameInfo() { - if (DwarfFrameInfos.empty()) - return nullptr; - return &DwarfFrameInfos.back(); -} - bool MCStreamer::hasUnfinishedDwarfFrameInfo() { - MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); - return CurFrame && !CurFrame->End; + return !DwarfFrameInfos.empty() && !DwarfFrameInfos.back().End; } -void MCStreamer::EnsureValidDwarfFrame() { - MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); - if (!CurFrame || CurFrame->End) - report_fatal_error("No open frame"); +MCDwarfFrameInfo *MCStreamer::getCurrentDwarfFrameInfo() { + if (!hasUnfinishedDwarfFrameInfo()) { + getContext().reportError(SMLoc(), "this directive must appear between " + ".cfi_startproc and .cfi_endproc " + "directives"); + return nullptr; + } + return &DwarfFrameInfos.back(); } -bool MCStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename) { - return getContext().getCVContext().addFile(FileNo, Filename); +bool MCStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename, + ArrayRef<uint8_t> Checksum, + unsigned ChecksumKind) { + return getContext().getCVContext().addFile(*this, FileNo, Filename, Checksum, + ChecksumKind); } bool MCStreamer::EmitCVFuncIdDirective(unsigned FunctionId) { @@ -322,7 +321,8 @@ void MCStreamer::EmitCFISections(bool EH, bool Debug) { void MCStreamer::EmitCFIStartProc(bool IsSimple) { if (hasUnfinishedDwarfFrameInfo()) - report_fatal_error("Starting a frame before finishing the previous one!"); + getContext().reportError( + SMLoc(), "starting new .cfi frame before finishing the previous one"); MCDwarfFrameInfo Frame; Frame.IsSimple = IsSimple; @@ -345,241 +345,298 @@ void MCStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) { } void MCStreamer::EmitCFIEndProc() { - EnsureValidDwarfFrame(); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; EmitCFIEndProcImpl(*CurFrame); } void MCStreamer::EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { // Put a dummy non-null value in Frame.End to mark that this frame has been // closed. - Frame.End = (MCSymbol *) 1; + Frame.End = (MCSymbol *)1; } MCSymbol *MCStreamer::EmitCFILabel() { - MCSymbol *Label = getContext().createTempSymbol("cfi", true); - EmitLabel(Label); - return Label; -} - -MCSymbol *MCStreamer::EmitCFICommon() { - EnsureValidDwarfFrame(); - return EmitCFILabel(); + // Return a dummy non-null value so that label fields appear filled in when + // generating textual assembly. + return (MCSymbol *)1; } void MCStreamer::EmitCFIDefCfa(int64_t Register, int64_t Offset) { - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createDefCfa(Label, Register, Offset); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); CurFrame->CurrentCfaRegister = static_cast<unsigned>(Register); } void MCStreamer::EmitCFIDefCfaOffset(int64_t Offset) { - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createDefCfaOffset(Label, Offset); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); } void MCStreamer::EmitCFIAdjustCfaOffset(int64_t Adjustment) { - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createAdjustCfaOffset(Label, Adjustment); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); } void MCStreamer::EmitCFIDefCfaRegister(int64_t Register) { - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createDefCfaRegister(Label, Register); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); CurFrame->CurrentCfaRegister = static_cast<unsigned>(Register); } void MCStreamer::EmitCFIOffset(int64_t Register, int64_t Offset) { - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createOffset(Label, Register, Offset); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); } void MCStreamer::EmitCFIRelOffset(int64_t Register, int64_t Offset) { - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createRelOffset(Label, Register, Offset); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); } void MCStreamer::EmitCFIPersonality(const MCSymbol *Sym, unsigned Encoding) { - EnsureValidDwarfFrame(); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Personality = Sym; CurFrame->PersonalityEncoding = Encoding; } void MCStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) { - EnsureValidDwarfFrame(); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Lsda = Sym; CurFrame->LsdaEncoding = Encoding; } void MCStreamer::EmitCFIRememberState() { - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createRememberState(Label); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); } void MCStreamer::EmitCFIRestoreState() { // FIXME: Error if there is no matching cfi_remember_state. - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createRestoreState(Label); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); } void MCStreamer::EmitCFISameValue(int64_t Register) { - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createSameValue(Label, Register); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); } void MCStreamer::EmitCFIRestore(int64_t Register) { - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createRestore(Label, Register); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); } void MCStreamer::EmitCFIEscape(StringRef Values) { - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createEscape(Label, Values); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); } void MCStreamer::EmitCFIGnuArgsSize(int64_t Size) { - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createGnuArgsSize(Label, Size); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); } void MCStreamer::EmitCFISignalFrame() { - EnsureValidDwarfFrame(); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->IsSignalFrame = true; } void MCStreamer::EmitCFIUndefined(int64_t Register) { - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createUndefined(Label, Register); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); } void MCStreamer::EmitCFIRegister(int64_t Register1, int64_t Register2) { - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createRegister(Label, Register1, Register2); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); } void MCStreamer::EmitCFIWindowSave() { - MCSymbol *Label = EmitCFICommon(); + MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createWindowSave(Label); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; CurFrame->Instructions.push_back(Instruction); } -void MCStreamer::EnsureValidWinFrameInfo() { +void MCStreamer::EmitCFIReturnColumn(int64_t Register) { + MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; + CurFrame->RAReg = Register; +} + +WinEH::FrameInfo *MCStreamer::EnsureValidWinFrameInfo(SMLoc Loc) { const MCAsmInfo *MAI = Context.getAsmInfo(); - if (!MAI->usesWindowsCFI()) - report_fatal_error(".seh_* directives are not supported on this target"); - if (!CurrentWinFrameInfo || CurrentWinFrameInfo->End) - report_fatal_error("No open Win64 EH frame function!"); + if (!MAI->usesWindowsCFI()) { + getContext().reportError( + Loc, ".seh_* directives are not supported on this target"); + return nullptr; + } + if (!CurrentWinFrameInfo || CurrentWinFrameInfo->End) { + getContext().reportError( + Loc, ".seh_ directive must appear within an active frame"); + return nullptr; + } + return CurrentWinFrameInfo; } -void MCStreamer::EmitWinCFIStartProc(const MCSymbol *Symbol) { +void MCStreamer::EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) { const MCAsmInfo *MAI = Context.getAsmInfo(); if (!MAI->usesWindowsCFI()) - report_fatal_error(".seh_* directives are not supported on this target"); + return getContext().reportError( + Loc, ".seh_* directives are not supported on this target"); if (CurrentWinFrameInfo && !CurrentWinFrameInfo->End) - report_fatal_error("Starting a function before ending the previous one!"); + getContext().reportError( + Loc, "Starting a function before ending the previous one!"); MCSymbol *StartProc = EmitCFILabel(); - WinFrameInfos.push_back(new WinEH::FrameInfo(Symbol, StartProc)); - CurrentWinFrameInfo = WinFrameInfos.back(); + WinFrameInfos.emplace_back( + llvm::make_unique<WinEH::FrameInfo>(Symbol, StartProc)); + CurrentWinFrameInfo = WinFrameInfos.back().get(); CurrentWinFrameInfo->TextSection = getCurrentSectionOnly(); } -void MCStreamer::EmitWinCFIEndProc() { - EnsureValidWinFrameInfo(); - if (CurrentWinFrameInfo->ChainedParent) - report_fatal_error("Not all chained regions terminated!"); +void MCStreamer::EmitWinCFIEndProc(SMLoc Loc) { + WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); + if (!CurFrame) + return; + if (CurFrame->ChainedParent) + getContext().reportError(Loc, "Not all chained regions terminated!"); MCSymbol *Label = EmitCFILabel(); - CurrentWinFrameInfo->End = Label; + CurFrame->End = Label; } -void MCStreamer::EmitWinCFIStartChained() { - EnsureValidWinFrameInfo(); +void MCStreamer::EmitWinCFIStartChained(SMLoc Loc) { + WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); + if (!CurFrame) + return; MCSymbol *StartProc = EmitCFILabel(); - WinFrameInfos.push_back(new WinEH::FrameInfo(CurrentWinFrameInfo->Function, - StartProc, CurrentWinFrameInfo)); - CurrentWinFrameInfo = WinFrameInfos.back(); + WinFrameInfos.emplace_back(llvm::make_unique<WinEH::FrameInfo>( + CurFrame->Function, StartProc, CurFrame)); + CurrentWinFrameInfo = WinFrameInfos.back().get(); CurrentWinFrameInfo->TextSection = getCurrentSectionOnly(); } -void MCStreamer::EmitWinCFIEndChained() { - EnsureValidWinFrameInfo(); - if (!CurrentWinFrameInfo->ChainedParent) - report_fatal_error("End of a chained region outside a chained region!"); +void MCStreamer::EmitWinCFIEndChained(SMLoc Loc) { + WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); + if (!CurFrame) + return; + if (!CurFrame->ChainedParent) + return getContext().reportError( + Loc, "End of a chained region outside a chained region!"); MCSymbol *Label = EmitCFILabel(); - CurrentWinFrameInfo->End = Label; - CurrentWinFrameInfo = - const_cast<WinEH::FrameInfo *>(CurrentWinFrameInfo->ChainedParent); + CurFrame->End = Label; + CurrentWinFrameInfo = const_cast<WinEH::FrameInfo *>(CurFrame->ChainedParent); } -void MCStreamer::EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, - bool Except) { - EnsureValidWinFrameInfo(); - if (CurrentWinFrameInfo->ChainedParent) - report_fatal_error("Chained unwind areas can't have handlers!"); - CurrentWinFrameInfo->ExceptionHandler = Sym; +void MCStreamer::EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except, + SMLoc Loc) { + WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); + if (!CurFrame) + return; + if (CurFrame->ChainedParent) + return getContext().reportError( + Loc, "Chained unwind areas can't have handlers!"); + CurFrame->ExceptionHandler = Sym; if (!Except && !Unwind) - report_fatal_error("Don't know what kind of handler this is!"); + getContext().reportError(Loc, "Don't know what kind of handler this is!"); if (Unwind) - CurrentWinFrameInfo->HandlesUnwind = true; + CurFrame->HandlesUnwind = true; if (Except) - CurrentWinFrameInfo->HandlesExceptions = true; + CurFrame->HandlesExceptions = true; } -void MCStreamer::EmitWinEHHandlerData() { - EnsureValidWinFrameInfo(); - if (CurrentWinFrameInfo->ChainedParent) - report_fatal_error("Chained unwind areas can't have handlers!"); +void MCStreamer::EmitWinEHHandlerData(SMLoc Loc) { + WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); + if (!CurFrame) + return; + if (CurFrame->ChainedParent) + getContext().reportError(Loc, "Chained unwind areas can't have handlers!"); } static MCSection *getWinCFISection(MCContext &Context, unsigned *NextWinCFIID, @@ -616,86 +673,110 @@ MCSection *MCStreamer::getAssociatedXDataSection(const MCSection *TextSec) { void MCStreamer::EmitSyntaxDirective() {} -void MCStreamer::EmitWinCFIPushReg(unsigned Register) { - EnsureValidWinFrameInfo(); +void MCStreamer::EmitWinCFIPushReg(unsigned Register, SMLoc Loc) { + WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); + if (!CurFrame) + return; MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::PushNonVol(Label, Register); - CurrentWinFrameInfo->Instructions.push_back(Inst); + CurFrame->Instructions.push_back(Inst); } -void MCStreamer::EmitWinCFISetFrame(unsigned Register, unsigned Offset) { - EnsureValidWinFrameInfo(); - if (CurrentWinFrameInfo->LastFrameInst >= 0) - report_fatal_error("Frame register and offset already specified!"); +void MCStreamer::EmitWinCFISetFrame(unsigned Register, unsigned Offset, + SMLoc Loc) { + WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); + if (!CurFrame) + return; + if (CurFrame->LastFrameInst >= 0) + return getContext().reportError( + Loc, "frame register and offset can be set at most once"); if (Offset & 0x0F) - report_fatal_error("Misaligned frame pointer offset!"); + return getContext().reportError(Loc, "offset is not a multiple of 16"); if (Offset > 240) - report_fatal_error("Frame offset must be less than or equal to 240!"); + return getContext().reportError( + Loc, "frame offset must be less than or equal to 240"); MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::SetFPReg(Label, Register, Offset); - CurrentWinFrameInfo->LastFrameInst = CurrentWinFrameInfo->Instructions.size(); - CurrentWinFrameInfo->Instructions.push_back(Inst); + CurFrame->LastFrameInst = CurFrame->Instructions.size(); + CurFrame->Instructions.push_back(Inst); } -void MCStreamer::EmitWinCFIAllocStack(unsigned Size) { - EnsureValidWinFrameInfo(); +void MCStreamer::EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) { + WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); + if (!CurFrame) + return; if (Size == 0) - report_fatal_error("Allocation size must be non-zero!"); + return getContext().reportError(Loc, + "stack allocation size must be non-zero"); if (Size & 7) - report_fatal_error("Misaligned stack allocation!"); + return getContext().reportError( + Loc, "stack allocation size is not a multiple of 8"); MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::Alloc(Label, Size); - CurrentWinFrameInfo->Instructions.push_back(Inst); + CurFrame->Instructions.push_back(Inst); } -void MCStreamer::EmitWinCFISaveReg(unsigned Register, unsigned Offset) { - EnsureValidWinFrameInfo(); +void MCStreamer::EmitWinCFISaveReg(unsigned Register, unsigned Offset, + SMLoc Loc) { + WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); + if (!CurFrame) + return; + if (Offset & 7) - report_fatal_error("Misaligned saved register offset!"); + return getContext().reportError( + Loc, "register save offset is not 8 byte aligned"); MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::SaveNonVol(Label, Register, Offset); - CurrentWinFrameInfo->Instructions.push_back(Inst); + CurFrame->Instructions.push_back(Inst); } -void MCStreamer::EmitWinCFISaveXMM(unsigned Register, unsigned Offset) { - EnsureValidWinFrameInfo(); +void MCStreamer::EmitWinCFISaveXMM(unsigned Register, unsigned Offset, + SMLoc Loc) { + WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); + if (!CurFrame) + return; if (Offset & 0x0F) - report_fatal_error("Misaligned saved vector register offset!"); + return getContext().reportError(Loc, "offset is not a multiple of 16"); MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::SaveXMM(Label, Register, Offset); - CurrentWinFrameInfo->Instructions.push_back(Inst); + CurFrame->Instructions.push_back(Inst); } -void MCStreamer::EmitWinCFIPushFrame(bool Code) { - EnsureValidWinFrameInfo(); - if (!CurrentWinFrameInfo->Instructions.empty()) - report_fatal_error("If present, PushMachFrame must be the first UOP"); +void MCStreamer::EmitWinCFIPushFrame(bool Code, SMLoc Loc) { + WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); + if (!CurFrame) + return; + if (!CurFrame->Instructions.empty()) + return getContext().reportError( + Loc, "If present, PushMachFrame must be the first UOP"); MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::PushMachFrame(Label, Code); - CurrentWinFrameInfo->Instructions.push_back(Inst); + CurFrame->Instructions.push_back(Inst); } -void MCStreamer::EmitWinCFIEndProlog() { - EnsureValidWinFrameInfo(); +void MCStreamer::EmitWinCFIEndProlog(SMLoc Loc) { + WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); + if (!CurFrame) + return; MCSymbol *Label = EmitCFILabel(); - CurrentWinFrameInfo->PrologEnd = Label; + CurFrame->PrologEnd = Label; } void MCStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) { @@ -725,7 +806,9 @@ void MCStreamer::EmitWindowsUnwindTables() { void MCStreamer::Finish() { if (!DwarfFrameInfos.empty() && !DwarfFrameInfos.back().End) - report_fatal_error("Unfinished frame!"); + getContext().reportError(SMLoc(), "Unfinished frame!"); + if (!WinFrameInfos.empty() && !WinFrameInfos.back()->End) + getContext().reportError(SMLoc(), "Unfinished frame!"); MCTargetStreamer *TS = getTargetStreamer(); if (TS) @@ -876,3 +959,32 @@ MCSymbol *MCStreamer::endSection(MCSection *Section) { EmitLabel(Sym); return Sym; } + +void MCStreamer::EmitVersionForTarget(const Triple &Target) { + if (!Target.isOSBinFormatMachO() || !Target.isOSDarwin()) + return; + // Do we even know the version? + if (Target.getOSMajorVersion() == 0) + return; + + unsigned Major; + unsigned Minor; + unsigned Update; + MCVersionMinType VersionType; + if (Target.isWatchOS()) { + VersionType = MCVM_WatchOSVersionMin; + Target.getWatchOSVersion(Major, Minor, Update); + } else if (Target.isTvOS()) { + VersionType = MCVM_TvOSVersionMin; + Target.getiOSVersion(Major, Minor, Update); + } else if (Target.isMacOSX()) { + VersionType = MCVM_OSXVersionMin; + if (!Target.getMacOSXVersion(Major, Minor, Update)) + Major = 0; + } else { + VersionType = MCVM_IOSVersionMin; + Target.getiOSVersion(Major, Minor, Update); + } + if (Major != 0) + EmitVersionMin(VersionType, Major, Minor, Update); +} diff --git a/lib/MC/MCSubtargetInfo.cpp b/lib/MC/MCSubtargetInfo.cpp index 385cdcc62320..8b9b076382e2 100644 --- a/lib/MC/MCSubtargetInfo.cpp +++ b/lib/MC/MCSubtargetInfo.cpp @@ -75,6 +75,18 @@ FeatureBitset MCSubtargetInfo::ApplyFeatureFlag(StringRef FS) { return FeatureBits; } +bool MCSubtargetInfo::checkFeatures(StringRef FS) const { + SubtargetFeatures T(FS); + FeatureBitset Set, All; + for (std::string F : T.getFeatures()) { + SubtargetFeatures::ApplyFeatureFlag(Set, F, ProcFeatures); + if (F[0] == '-') + F[0] = '+'; + SubtargetFeatures::ApplyFeatureFlag(All, F, ProcFeatures); + } + return (FeatureBits & All) == Set; +} + const MCSchedModel &MCSubtargetInfo::getSchedModelForCPU(StringRef CPU) const { assert(ProcSchedModels && "Processor machine model not available!"); @@ -102,7 +114,7 @@ const MCSchedModel &MCSubtargetInfo::getSchedModelForCPU(StringRef CPU) const { InstrItineraryData MCSubtargetInfo::getInstrItineraryForCPU(StringRef CPU) const { - const MCSchedModel SchedModel = getSchedModelForCPU(CPU); + const MCSchedModel &SchedModel = getSchedModelForCPU(CPU); return InstrItineraryData(SchedModel, Stages, OperandCycles, ForwardingPaths); } diff --git a/lib/MC/MCSymbolELF.cpp b/lib/MC/MCSymbolELF.cpp index 67449eb6dcf9..12c724f6b1ee 100644 --- a/lib/MC/MCSymbolELF.cpp +++ b/lib/MC/MCSymbolELF.cpp @@ -9,7 +9,6 @@ #include "llvm/MC/MCSymbolELF.h" #include "llvm/BinaryFormat/ELF.h" -#include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCFixupKindInfo.h" namespace llvm { diff --git a/lib/MC/MCWasmStreamer.cpp b/lib/MC/MCWasmStreamer.cpp index 02fa070f0c57..d9cefbd3994f 100644 --- a/lib/MC/MCWasmStreamer.cpp +++ b/lib/MC/MCWasmStreamer.cpp @@ -15,16 +15,13 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/MC/MCAsmBackend.h" -#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" -#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectStreamer.h" -#include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCSymbol.h" @@ -98,9 +95,13 @@ bool MCWasmStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { case MCSA_WeakDefAutoPrivate: case MCSA_Invalid: case MCSA_IndirectSymbol: - case MCSA_Hidden: + case MCSA_Protected: return false; + case MCSA_Hidden: + Symbol->setHidden(true); + break; + case MCSA_Weak: case MCSA_WeakReference: Symbol->setWeak(true); @@ -156,7 +157,7 @@ void MCWasmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, void MCWasmStreamer::EmitIdent(StringRef IdentString) { MCSection *Comment = getAssembler().getContext().getWasmSection( - ".comment", 0, 0); + ".comment", SectionKind::getMetadata()); PushSection(); SwitchSection(Comment); if (!SeenIdent) { @@ -200,10 +201,13 @@ void MCWasmStreamer::FinishImpl() { this->MCObjectStreamer::FinishImpl(); } -MCStreamer *llvm::createWasmStreamer(MCContext &Context, MCAsmBackend &MAB, - raw_pwrite_stream &OS, MCCodeEmitter *CE, +MCStreamer *llvm::createWasmStreamer(MCContext &Context, + std::unique_ptr<MCAsmBackend> &&MAB, + raw_pwrite_stream &OS, + std::unique_ptr<MCCodeEmitter> &&CE, bool RelaxAll) { - MCWasmStreamer *S = new MCWasmStreamer(Context, MAB, OS, CE); + MCWasmStreamer *S = + new MCWasmStreamer(Context, std::move(MAB), OS, std::move(CE)); if (RelaxAll) S->getAssembler().setRelaxAll(true); return S; diff --git a/lib/MC/MCWin64EH.cpp b/lib/MC/MCWin64EH.cpp index fdc4c10cd6ce..1407f25e6f2a 100644 --- a/lib/MC/MCWin64EH.cpp +++ b/lib/MC/MCWin64EH.cpp @@ -11,8 +11,6 @@ #include "llvm/ADT/Twine.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCObjectFileInfo.h" -#include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/Win64EH.h" @@ -220,17 +218,17 @@ static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) { void llvm::Win64EH::UnwindEmitter::Emit(MCStreamer &Streamer) const { // Emit the unwind info structs first. - for (WinEH::FrameInfo *CFI : Streamer.getWinFrameInfos()) { + for (const auto &CFI : Streamer.getWinFrameInfos()) { MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection); Streamer.SwitchSection(XData); - ::EmitUnwindInfo(Streamer, CFI); + ::EmitUnwindInfo(Streamer, CFI.get()); } // Now emit RUNTIME_FUNCTION entries. - for (WinEH::FrameInfo *CFI : Streamer.getWinFrameInfos()) { + for (const auto &CFI : Streamer.getWinFrameInfos()) { MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection); Streamer.SwitchSection(PData); - EmitRuntimeFunction(Streamer, CFI); + EmitRuntimeFunction(Streamer, CFI.get()); } } diff --git a/lib/MC/MCWinCOFFStreamer.cpp b/lib/MC/MCWinCOFFStreamer.cpp index bf341bb1f451..c2583d95c5ed 100644 --- a/lib/MC/MCWinCOFFStreamer.cpp +++ b/lib/MC/MCWinCOFFStreamer.cpp @@ -41,9 +41,12 @@ using namespace llvm; #define DEBUG_TYPE "WinCOFFStreamer" -MCWinCOFFStreamer::MCWinCOFFStreamer(MCContext &Context, MCAsmBackend &MAB, - MCCodeEmitter &CE, raw_pwrite_stream &OS) - : MCObjectStreamer(Context, MAB, OS, &CE), CurSymbol(nullptr) {} +MCWinCOFFStreamer::MCWinCOFFStreamer(MCContext &Context, + std::unique_ptr<MCAsmBackend> MAB, + std::unique_ptr<MCCodeEmitter> CE, + raw_pwrite_stream &OS) + : MCObjectStreamer(Context, std::move(MAB), OS, std::move(CE)), + CurSymbol(nullptr) {} void MCWinCOFFStreamer::EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &STI) { @@ -179,7 +182,7 @@ void MCWinCOFFStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) { if (SXData->getAlignment() < 4) SXData->setAlignment(4); - new MCSafeSEHFragment(Symbol, SXData); + new MCSymbolIdFragment(Symbol, SXData); getAssembler().registerSymbol(*Symbol); CSymbol->setIsSafeSEH(); @@ -285,7 +288,7 @@ void MCWinCOFFStreamer::EmitIdent(StringRef IdentString) { llvm_unreachable("not implemented"); } -void MCWinCOFFStreamer::EmitWinEHHandlerData() { +void MCWinCOFFStreamer::EmitWinEHHandlerData(SMLoc Loc) { llvm_unreachable("not implemented"); } diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp index 62bf0a58fdfa..c7eaa76ace3c 100644 --- a/lib/MC/MachObjectWriter.cpp +++ b/lib/MC/MachObjectWriter.cpp @@ -721,6 +721,16 @@ bool MachObjectWriter::isSymbolRefDifferenceFullyResolvedImpl( return false; } +static MachO::LoadCommandType getLCFromMCVM(MCVersionMinType Type) { + switch (Type) { + case MCVM_OSXVersionMin: return MachO::LC_VERSION_MIN_MACOSX; + case MCVM_IOSVersionMin: return MachO::LC_VERSION_MIN_IPHONEOS; + case MCVM_TvOSVersionMin: return MachO::LC_VERSION_MIN_TVOS; + case MCVM_WatchOSVersionMin: return MachO::LC_VERSION_MIN_WATCHOS; + } + llvm_unreachable("Invalid mc version min type"); +} + void MachObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { // Compute symbol table information and bind symbol indices. @@ -728,8 +738,8 @@ void MachObjectWriter::writeObject(MCAssembler &Asm, UndefinedSymbolData); unsigned NumSections = Asm.size(); - const MCAssembler::VersionMinInfoType &VersionInfo = - Layout.getAssembler().getVersionMinInfo(); + const MCAssembler::VersionInfoType &VersionInfo = + Layout.getAssembler().getVersionInfo(); // The section data starts after the header, the segment load command (and // section headers) and the symbol table. @@ -741,7 +751,10 @@ void MachObjectWriter::writeObject(MCAssembler &Asm, // Add the deployment target version info load command size, if used. if (VersionInfo.Major != 0) { ++NumLoadCommands; - LoadCommandsSize += sizeof(MachO::version_min_command); + if (VersionInfo.EmitBuildVersion) + LoadCommandsSize += sizeof(MachO::build_version_command); + else + LoadCommandsSize += sizeof(MachO::version_min_command); } // Add the data-in-code load command size, if used. @@ -832,25 +845,22 @@ void MachObjectWriter::writeObject(MCAssembler &Asm, assert(VersionInfo.Major < 65536 && "unencodable major target version"); uint32_t EncodedVersion = VersionInfo.Update | (VersionInfo.Minor << 8) | (VersionInfo.Major << 16); - MachO::LoadCommandType LCType; - switch (VersionInfo.Kind) { - case MCVM_OSXVersionMin: - LCType = MachO::LC_VERSION_MIN_MACOSX; - break; - case MCVM_IOSVersionMin: - LCType = MachO::LC_VERSION_MIN_IPHONEOS; - break; - case MCVM_TvOSVersionMin: - LCType = MachO::LC_VERSION_MIN_TVOS; - break; - case MCVM_WatchOSVersionMin: - LCType = MachO::LC_VERSION_MIN_WATCHOS; - break; + if (VersionInfo.EmitBuildVersion) { + // FIXME: Currently empty tools. Add clang version in the future. + write32(MachO::LC_BUILD_VERSION); + write32(sizeof(MachO::build_version_command)); + write32(VersionInfo.TypeOrPlatform.Platform); + write32(EncodedVersion); + write32(0); // SDK version. + write32(0); // Empty tools list. + } else { + MachO::LoadCommandType LCType + = getLCFromMCVM(VersionInfo.TypeOrPlatform.Type); + write32(LCType); + write32(sizeof(MachO::version_min_command)); + write32(EncodedVersion); + write32(0); // reserved. } - write32(LCType); - write32(sizeof(MachO::version_min_command)); - write32(EncodedVersion); - write32(0); // reserved. } // Write the data-in-code load command, if used. @@ -994,8 +1004,9 @@ void MachObjectWriter::writeObject(MCAssembler &Asm, } } -MCObjectWriter *llvm::createMachObjectWriter(MCMachObjectTargetWriter *MOTW, - raw_pwrite_stream &OS, - bool IsLittleEndian) { - return new MachObjectWriter(MOTW, OS, IsLittleEndian); +std::unique_ptr<MCObjectWriter> +llvm::createMachObjectWriter(std::unique_ptr<MCMachObjectTargetWriter> MOTW, + raw_pwrite_stream &OS, bool IsLittleEndian) { + return llvm::make_unique<MachObjectWriter>(std::move(MOTW), OS, + IsLittleEndian); } diff --git a/lib/MC/StringTableBuilder.cpp b/lib/MC/StringTableBuilder.cpp index 6025a20a9c19..531bc930c89b 100644 --- a/lib/MC/StringTableBuilder.cpp +++ b/lib/MC/StringTableBuilder.cpp @@ -82,32 +82,34 @@ static int charTailAt(StringPair *P, size_t Pos) { // Three-way radix quicksort. This is much faster than std::sort with strcmp // because it does not compare characters that we already know the same. -static void multikey_qsort(StringPair **Begin, StringPair **End, int Pos) { +static void multikeySort(MutableArrayRef<StringPair *> Vec, int Pos) { tailcall: - if (End - Begin <= 1) + if (Vec.size() <= 1) return; - // Partition items. Items in [Begin, P) are greater than the pivot, - // [P, Q) are the same as the pivot, and [Q, End) are less than the pivot. - int Pivot = charTailAt(*Begin, Pos); - StringPair **P = Begin; - StringPair **Q = End; - for (StringPair **R = Begin + 1; R < Q;) { - int C = charTailAt(*R, Pos); + // Partition items so that items in [0, I) are greater than the pivot, + // [I, J) are the same as the pivot, and [J, Vec.size()) are less than + // the pivot. + int Pivot = charTailAt(Vec[0], Pos); + size_t I = 0; + size_t J = Vec.size(); + for (size_t K = 1; K < J;) { + int C = charTailAt(Vec[K], Pos); if (C > Pivot) - std::swap(*P++, *R++); + std::swap(Vec[I++], Vec[K++]); else if (C < Pivot) - std::swap(*--Q, *R); + std::swap(Vec[--J], Vec[K]); else - R++; + K++; } - multikey_qsort(Begin, P, Pos); - multikey_qsort(Q, End, Pos); + multikeySort(Vec.slice(0, I), Pos); + multikeySort(Vec.slice(J), Pos); + + // multikeySort(Vec.slice(I, J - I), Pos + 1), but with + // tail call optimization. if (Pivot != -1) { - // qsort(P, Q, Pos + 1), but with tail call optimization. - Begin = P; - End = Q; + Vec = Vec.slice(I, J - I); ++Pos; goto tailcall; } @@ -130,12 +132,7 @@ void StringTableBuilder::finalizeStringTable(bool Optimize) { for (StringPair &P : StringIndexMap) Strings.push_back(&P); - if (!Strings.empty()) { - // If we're optimizing, sort by name. If not, sort by previously assigned - // offset. - multikey_qsort(&Strings[0], &Strings[0] + Strings.size(), 0); - } - + multikeySort(Strings, 0); initSize(); StringRef Previous; diff --git a/lib/MC/WasmObjectWriter.cpp b/lib/MC/WasmObjectWriter.cpp index 0d31f65c49d9..6e76c5fac35f 100644 --- a/lib/MC/WasmObjectWriter.cpp +++ b/lib/MC/WasmObjectWriter.cpp @@ -15,13 +15,11 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/BinaryFormat/Wasm.h" #include "llvm/MC/MCAsmBackend.h" -#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixupKindInfo.h" -#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCSymbolWasm.h" @@ -96,12 +94,26 @@ struct WasmFunctionTypeDenseMapInfo { } }; +// A wasm data segment. A wasm binary contains only a single data section +// but that can contain many segments, each with their own virtual location +// in memory. Each MCSection data created by llvm is modeled as its own +// wasm data segment. +struct WasmDataSegment { + MCSectionWasm *Section; + StringRef Name; + uint32_t Offset; + uint32_t Alignment; + uint32_t Flags; + SmallVector<char, 4> Data; +}; + // A wasm import to be written into the import section. struct WasmImport { StringRef ModuleName; StringRef FieldName; unsigned Kind; int32_t Type; + bool IsMutable; }; // A wasm function to be written into the function section. @@ -142,9 +154,9 @@ struct WasmRelocationEntry { bool hasAddend() const { switch (Type) { - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: return true; default: return false; @@ -153,7 +165,8 @@ struct WasmRelocationEntry { void print(raw_ostream &Out) const { Out << "Off=" << Offset << ", Sym=" << *Symbol << ", Addend=" << Addend - << ", Type=" << Type << ", FixupSection=" << FixupSection; + << ", Type=" << Type + << ", FixupSection=" << FixupSection->getSectionName(); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) @@ -199,6 +212,8 @@ class WasmObjectWriter : public MCObjectWriter { DenseMap<WasmFunctionType, int32_t, WasmFunctionTypeDenseMapInfo> FunctionTypeIndices; SmallVector<WasmFunctionType, 4> FunctionTypes; + SmallVector<WasmGlobal, 4> Globals; + unsigned NumGlobalImports = 0; // TargetObjectWriter wrappers. bool is64Bit() const { return TargetObjectWriter->is64Bit(); } @@ -211,8 +226,10 @@ class WasmObjectWriter : public MCObjectWriter { void endSection(SectionBookkeeping &Section); public: - WasmObjectWriter(MCWasmObjectTargetWriter *MOTW, raw_pwrite_stream &OS) - : MCObjectWriter(OS, /*IsLittleEndian=*/true), TargetObjectWriter(MOTW) {} + WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW, + raw_pwrite_stream &OS) + : MCObjectWriter(OS, /*IsLittleEndian=*/true), + TargetObjectWriter(std::move(MOTW)) {} private: ~WasmObjectWriter() override; @@ -225,7 +242,9 @@ private: IndirectSymbolIndices.clear(); FunctionTypeIndices.clear(); FunctionTypes.clear(); + Globals.clear(); MCObjectWriter::reset(); + NumGlobalImports = 0; } void writeHeader(const MCAssembler &Asm); @@ -248,33 +267,31 @@ private: encodeSLEB128(int32_t(Ty), getStream()); } - void writeTypeSection(const SmallVector<WasmFunctionType, 4> &FunctionTypes); - void writeImportSection(const SmallVector<WasmImport, 4> &Imports); - void writeFunctionSection(const SmallVector<WasmFunction, 4> &Functions); - void writeTableSection(uint32_t NumElements); - void writeMemorySection(const SmallVector<char, 0> &DataBytes); - void writeGlobalSection(const SmallVector<WasmGlobal, 4> &Globals); - void writeExportSection(const SmallVector<WasmExport, 4> &Exports); - void writeElemSection(const SmallVector<uint32_t, 4> &TableElems); + void writeTypeSection(ArrayRef<WasmFunctionType> FunctionTypes); + void writeImportSection(ArrayRef<WasmImport> Imports, uint32_t DataSize, + uint32_t NumElements); + void writeFunctionSection(ArrayRef<WasmFunction> Functions); + void writeGlobalSection(); + void writeExportSection(ArrayRef<WasmExport> Exports); + void writeElemSection(ArrayRef<uint32_t> TableElems); void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, - const SmallVector<WasmFunction, 4> &Functions); - uint64_t - writeDataSection(const SmallVector<char, 0> &DataBytes); - void writeNameSection(const SmallVector<WasmFunction, 4> &Functions, - const SmallVector<WasmImport, 4> &Imports, + ArrayRef<WasmFunction> Functions); + void writeDataSection(ArrayRef<WasmDataSegment> Segments); + void writeNameSection(ArrayRef<WasmFunction> Functions, + ArrayRef<WasmImport> Imports, uint32_t NumFuncImports); void writeCodeRelocSection(); - void writeDataRelocSection(uint64_t DataSectionHeaderSize); - void writeLinkingMetaDataSection(uint32_t DataSize, uint32_t DataAlignment, - ArrayRef<StringRef> WeakSymbols, - bool HasStackPointer, - uint32_t StackPointerGlobal); + void writeDataRelocSection(); + void writeLinkingMetaDataSection( + ArrayRef<WasmDataSegment> Segments, uint32_t DataSize, + const SmallVector<std::pair<StringRef, uint32_t>, 4> &SymbolFlags, + const SmallVector<std::pair<uint16_t, uint32_t>, 2> &InitFuncs); + uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset); - void writeRelocations(ArrayRef<WasmRelocationEntry> Relocations, - uint64_t HeaderSize); + void writeRelocations(ArrayRef<WasmRelocationEntry> Relocations); uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry); uint32_t getFunctionType(const MCSymbolWasm& Symbol); uint32_t registerFunctionType(const MCSymbolWasm& Symbol); @@ -284,16 +301,6 @@ private: WasmObjectWriter::~WasmObjectWriter() {} -// Return the padding size to write a 32-bit value into a 5-byte ULEB128. -static unsigned PaddingFor5ByteULEB128(uint32_t X) { - return X == 0 ? 4 : (4u - (31u - countLeadingZeros(X)) / 7u); -} - -// Return the padding size to write a 32-bit value into a 5-byte SLEB128. -static unsigned PaddingFor5ByteSLEB128(int32_t X) { - return 5 - getSLEB128Size(X); -} - // Write out a section header and a patchable section size field. void WasmObjectWriter::startSection(SectionBookkeeping &Section, unsigned SectionId, @@ -328,12 +335,11 @@ void WasmObjectWriter::endSection(SectionBookkeeping &Section) { report_fatal_error("section size does not fit in a uint32_t"); DEBUG(dbgs() << "endSection size=" << Size << "\n"); - unsigned Padding = PaddingFor5ByteULEB128(Size); // Write the final section size to the payload_len field, which follows // the section id byte. uint8_t Buffer[16]; - unsigned SizeLen = encodeULEB128(Size, Buffer, Padding); + unsigned SizeLen = encodeULEB128(Size, Buffer, 5); assert(SizeLen == 5); getStream().pwrite((char *)Buffer, SizeLen, Section.SizeOffset); } @@ -361,6 +367,10 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); MCContext &Ctx = Asm.getContext(); + // The .init_array isn't translated as data, so don't do relocations in it. + if (FixupSection.getSectionName().startswith(".init_array")) + return; + if (const MCSymbolRefExpr *RefB = Target.getSymB()) { assert(RefB->getKind() == MCSymbolRefExpr::VK_None && "Should not have constructed this"); @@ -429,10 +439,13 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection); DEBUG(dbgs() << "WasmReloc: " << Rec << "\n"); - if (FixupSection.hasInstructions()) - CodeRelocations.push_back(Rec); - else + if (FixupSection.isWasmData()) DataRelocations.push_back(Rec); + else if (FixupSection.getKind().isText()) + CodeRelocations.push_back(Rec); + else if (!FixupSection.getKind().isMetadata()) + // TODO(sbc): Add support for debug sections. + llvm_unreachable("unexpected section type"); } // Write X as an (unsigned) LEB value at offset Offset in Stream, padded @@ -440,8 +453,7 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, static void WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { uint8_t Buffer[5]; - unsigned Padding = PaddingFor5ByteULEB128(X); - unsigned SizeLen = encodeULEB128(X, Buffer, Padding); + unsigned SizeLen = encodeULEB128(X, Buffer, 5); assert(SizeLen == 5); Stream.pwrite((char *)Buffer, SizeLen, Offset); } @@ -451,8 +463,7 @@ WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { static void WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, uint64_t Offset) { uint8_t Buffer[5]; - unsigned Padding = PaddingFor5ByteSLEB128(X); - unsigned SizeLen = encodeSLEB128(X, Buffer, Padding); + unsigned SizeLen = encodeSLEB128(X, Buffer, 5); assert(SizeLen == 5); Stream.pwrite((char *)Buffer, SizeLen, Offset); } @@ -464,19 +475,30 @@ 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) { + if (Symbol.isVariable()) { + const MCExpr *Expr = Symbol.getVariableValue(); + auto *Inner = cast<MCSymbolRefExpr>(Expr); + return cast<MCSymbolWasm>(&Inner->getSymbol()); + } + return &Symbol; +} + // Compute a value to write into the code at the location covered // by RelEntry. This value isn't used by the static linker, since // we have addends; it just serves to make the code more readable // and to make standalone wasm modules directly usable. -static uint32_t ProvisionalValue(const WasmRelocationEntry &RelEntry) { - const MCSymbolWasm *Sym = RelEntry.Symbol; +uint32_t +WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { + const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol); // For undefined symbols, use a hopefully invalid value. if (!Sym->isDefined(/*SetUsed=*/false)) return UINT32_MAX; - const auto &Section = cast<MCSectionWasm>(RelEntry.Symbol->getSection(false)); - uint64_t Address = Section.getSectionOffset() + RelEntry.Addend; + uint32_t GlobalIndex = SymbolIndices[Sym]; + const WasmGlobal& Global = Globals[GlobalIndex - NumGlobalImports]; + uint64_t Address = Global.InitialValue + RelEntry.Addend; // Ignore overflow. LLVM allows address arithmetic to silently wrap. uint32_t Value = Address; @@ -484,6 +506,47 @@ static uint32_t ProvisionalValue(const WasmRelocationEntry &RelEntry) { return Value; } +static void addData(SmallVectorImpl<char> &DataBytes, + MCSectionWasm &DataSection) { + DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n"); + + DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); + + size_t LastFragmentSize = 0; + for (const MCFragment &Frag : DataSection) { + if (Frag.hasInstructions()) + report_fatal_error("only data supported in data sections"); + + if (auto *Align = dyn_cast<MCAlignFragment>(&Frag)) { + if (Align->getValueSize() != 1) + 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()); + DataBytes.resize(Size, Value); + } else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) { + DataBytes.insert(DataBytes.end(), Fill->getSize(), Fill->getValue()); + } else { + const auto &DataFrag = cast<MCDataFragment>(Frag); + const SmallVectorImpl<char> &Contents = DataFrag.getContents(); + + DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); + LastFragmentSize = Contents.size(); + } + } + + // Don't allow empty segments, or segments that end with zero-sized + // fragment, otherwise the linker cannot map symbols to a unique + // data segment. This can be triggered by zero-sized structs + // See: test/MC/WebAssembly/bss.ll + if (LastFragmentSize == 0) + DataBytes.resize(DataBytes.size() + 1); + DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n"); +} + uint32_t WasmObjectWriter::getRelocationIndexValue( const WasmRelocationEntry &RelEntry) { switch (RelEntry.Type) { @@ -495,9 +558,9 @@ uint32_t WasmObjectWriter::getRelocationIndexValue( return IndirectSymbolIndices[RelEntry.Symbol]; case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: if (!SymbolIndices.count(RelEntry.Symbol)) report_fatal_error("symbol not found function/global index space: " + RelEntry.Symbol->getName()); @@ -537,18 +600,18 @@ void WasmObjectWriter::applyRelocations( WriteI32(Stream, Index, Offset); break; } - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: { - uint32_t Value = ProvisionalValue(RelEntry); + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: { + uint32_t Value = getProvisionalValue(RelEntry); WritePatchableSLEB(Stream, Value, Offset); break; } - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: { - uint32_t Value = ProvisionalValue(RelEntry); + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: { + uint32_t Value = getProvisionalValue(RelEntry); WritePatchableLEB(Stream, Value, Offset); break; } - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: { - uint32_t Value = ProvisionalValue(RelEntry); + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: { + uint32_t Value = getProvisionalValue(RelEntry); WriteI32(Stream, Value, Offset); break; } @@ -561,12 +624,12 @@ void WasmObjectWriter::applyRelocations( // Write out the portions of the relocation records that the linker will // need to handle. void WasmObjectWriter::writeRelocations( - ArrayRef<WasmRelocationEntry> Relocations, uint64_t HeaderSize) { + ArrayRef<WasmRelocationEntry> Relocations) { raw_pwrite_stream &Stream = getStream(); for (const WasmRelocationEntry& RelEntry : Relocations) { uint64_t Offset = RelEntry.Offset + - RelEntry.FixupSection->getSectionOffset() + HeaderSize; + RelEntry.FixupSection->getSectionOffset(); uint32_t Index = getRelocationIndexValue(RelEntry); encodeULEB128(RelEntry.Type, Stream); @@ -578,7 +641,7 @@ void WasmObjectWriter::writeRelocations( } void WasmObjectWriter::writeTypeSection( - const SmallVector<WasmFunctionType, 4> &FunctionTypes) { + ArrayRef<WasmFunctionType> FunctionTypes) { if (FunctionTypes.empty()) return; @@ -600,12 +663,14 @@ void WasmObjectWriter::writeTypeSection( endSection(Section); } - -void WasmObjectWriter::writeImportSection( - const SmallVector<WasmImport, 4> &Imports) { +void WasmObjectWriter::writeImportSection(ArrayRef<WasmImport> Imports, + uint32_t DataSize, + uint32_t NumElements) { if (Imports.empty()) return; + uint32_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize; + SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_IMPORT); @@ -622,7 +687,16 @@ void WasmObjectWriter::writeImportSection( break; case wasm::WASM_EXTERNAL_GLOBAL: encodeSLEB128(int32_t(Import.Type), getStream()); - encodeULEB128(0, getStream()); // mutability + encodeULEB128(int32_t(Import.IsMutable), getStream()); + break; + case wasm::WASM_EXTERNAL_MEMORY: + encodeULEB128(0, getStream()); // flags + encodeULEB128(NumPages, getStream()); // initial + break; + case wasm::WASM_EXTERNAL_TABLE: + encodeSLEB128(int32_t(Import.Type), getStream()); + encodeULEB128(0, getStream()); // flags + encodeULEB128(NumElements, getStream()); // initial break; default: llvm_unreachable("unsupported import kind"); @@ -632,8 +706,7 @@ void WasmObjectWriter::writeImportSection( endSection(Section); } -void WasmObjectWriter::writeFunctionSection( - const SmallVector<WasmFunction, 4> &Functions) { +void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) { if (Functions.empty()) return; @@ -647,43 +720,7 @@ void WasmObjectWriter::writeFunctionSection( endSection(Section); } -void WasmObjectWriter::writeTableSection(uint32_t NumElements) { - // For now, always emit the table section, since indirect calls are not - // valid without it. In the future, we could perhaps be more clever and omit - // it if there are no indirect calls. - - SectionBookkeeping Section; - startSection(Section, wasm::WASM_SEC_TABLE); - - encodeULEB128(1, getStream()); // The number of tables. - // Fixed to 1 for now. - encodeSLEB128(wasm::WASM_TYPE_ANYFUNC, getStream()); // Type of table - encodeULEB128(0, getStream()); // flags - encodeULEB128(NumElements, getStream()); // initial - - endSection(Section); -} - -void WasmObjectWriter::writeMemorySection( - const SmallVector<char, 0> &DataBytes) { - // For now, always emit the memory section, since loads and stores are not - // valid without it. In the future, we could perhaps be more clever and omit - // it if there are no loads or stores. - SectionBookkeeping Section; - uint32_t NumPages = - (DataBytes.size() + wasm::WasmPageSize - 1) / wasm::WasmPageSize; - - startSection(Section, wasm::WASM_SEC_MEMORY); - encodeULEB128(1, getStream()); // number of memory spaces - - encodeULEB128(0, getStream()); // flags - encodeULEB128(NumPages, getStream()); // initial - - endSection(Section); -} - -void WasmObjectWriter::writeGlobalSection( - const SmallVector<WasmGlobal, 4> &Globals) { +void WasmObjectWriter::writeGlobalSection() { if (Globals.empty()) return; @@ -710,8 +747,7 @@ void WasmObjectWriter::writeGlobalSection( endSection(Section); } -void WasmObjectWriter::writeExportSection( - const SmallVector<WasmExport, 4> &Exports) { +void WasmObjectWriter::writeExportSection(ArrayRef<WasmExport> Exports) { if (Exports.empty()) return; @@ -728,8 +764,7 @@ void WasmObjectWriter::writeExportSection( endSection(Section); } -void WasmObjectWriter::writeElemSection( - const SmallVector<uint32_t, 4> &TableElems) { +void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) { if (TableElems.empty()) return; @@ -751,9 +786,9 @@ void WasmObjectWriter::writeElemSection( endSection(Section); } -void WasmObjectWriter::writeCodeSection( - const MCAssembler &Asm, const MCAsmLayout &Layout, - const SmallVector<WasmFunction, 4> &Functions) { +void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm, + const MCAsmLayout &Layout, + ArrayRef<WasmFunction> Functions) { if (Functions.empty()) return; @@ -770,9 +805,7 @@ void WasmObjectWriter::writeCodeSection( report_fatal_error(".size expression must be evaluatable"); encodeULEB128(Size, getStream()); - FuncSection.setSectionOffset(getStream().tell() - Section.ContentsOffset); - Asm.writeSectionData(&FuncSection, Layout); } @@ -782,33 +815,34 @@ void WasmObjectWriter::writeCodeSection( endSection(Section); } -uint64_t WasmObjectWriter::writeDataSection( - const SmallVector<char, 0> &DataBytes) { - if (DataBytes.empty()) - return 0; +void WasmObjectWriter::writeDataSection(ArrayRef<WasmDataSegment> Segments) { + if (Segments.empty()) + return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_DATA); - encodeULEB128(1, getStream()); // count - encodeULEB128(0, getStream()); // memory index - write8(wasm::WASM_OPCODE_I32_CONST); - encodeSLEB128(0, getStream()); // offset - write8(wasm::WASM_OPCODE_END); - encodeULEB128(DataBytes.size(), getStream()); // size - uint32_t HeaderSize = getStream().tell() - Section.ContentsOffset; - writeBytes(DataBytes); // data + encodeULEB128(Segments.size(), getStream()); // count + + for (const WasmDataSegment & Segment : Segments) { + encodeULEB128(0, getStream()); // memory index + write8(wasm::WASM_OPCODE_I32_CONST); + encodeSLEB128(Segment.Offset, getStream()); // offset + write8(wasm::WASM_OPCODE_END); + encodeULEB128(Segment.Data.size(), getStream()); // size + Segment.Section->setSectionOffset(getStream().tell() - Section.ContentsOffset); + writeBytes(Segment.Data); // data + } // Apply fixups. - applyRelocations(DataRelocations, Section.ContentsOffset + HeaderSize); + applyRelocations(DataRelocations, Section.ContentsOffset); endSection(Section); - return HeaderSize; } void WasmObjectWriter::writeNameSection( - const SmallVector<WasmFunction, 4> &Functions, - const SmallVector<WasmImport, 4> &Imports, + ArrayRef<WasmFunction> Functions, + ArrayRef<WasmImport> Imports, unsigned NumFuncImports) { uint32_t TotalFunctions = NumFuncImports + Functions.size(); if (TotalFunctions == 0) @@ -851,12 +885,12 @@ void WasmObjectWriter::writeCodeRelocSection() { encodeULEB128(wasm::WASM_SEC_CODE, getStream()); encodeULEB128(CodeRelocations.size(), getStream()); - writeRelocations(CodeRelocations, 0); + writeRelocations(CodeRelocations); endSection(Section); } -void WasmObjectWriter::writeDataRelocSection(uint64_t DataSectionHeaderSize) { +void WasmObjectWriter::writeDataRelocSection() { // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md // for descriptions of the reloc sections. @@ -869,30 +903,25 @@ void WasmObjectWriter::writeDataRelocSection(uint64_t DataSectionHeaderSize) { encodeULEB128(wasm::WASM_SEC_DATA, getStream()); encodeULEB128(DataRelocations.size(), getStream()); - writeRelocations(DataRelocations, DataSectionHeaderSize); + writeRelocations(DataRelocations); endSection(Section); } void WasmObjectWriter::writeLinkingMetaDataSection( - uint32_t DataSize, uint32_t DataAlignment, ArrayRef<StringRef> WeakSymbols, - bool HasStackPointer, uint32_t StackPointerGlobal) { + ArrayRef<WasmDataSegment> Segments, uint32_t DataSize, + const SmallVector<std::pair<StringRef, uint32_t>, 4> &SymbolFlags, + const SmallVector<std::pair<uint16_t, uint32_t>, 2> &InitFuncs) { SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_CUSTOM, "linking"); SectionBookkeeping SubSection; - if (HasStackPointer) { - startSection(SubSection, wasm::WASM_STACK_POINTER); - encodeULEB128(StackPointerGlobal, getStream()); // id - endSection(SubSection); - } - - if (WeakSymbols.size() != 0) { + if (SymbolFlags.size() != 0) { startSection(SubSection, wasm::WASM_SYMBOL_INFO); - encodeULEB128(WeakSymbols.size(), getStream()); - for (const StringRef Export: WeakSymbols) { - writeString(Export); - encodeULEB128(wasm::WASM_SYMBOL_FLAG_WEAK, getStream()); + encodeULEB128(SymbolFlags.size(), getStream()); + for (auto Pair: SymbolFlags) { + writeString(Pair.first); + encodeULEB128(Pair.second, getStream()); } endSection(SubSection); } @@ -901,9 +930,26 @@ void WasmObjectWriter::writeLinkingMetaDataSection( startSection(SubSection, wasm::WASM_DATA_SIZE); encodeULEB128(DataSize, getStream()); endSection(SubSection); + } - startSection(SubSection, wasm::WASM_DATA_ALIGNMENT); - encodeULEB128(DataAlignment, getStream()); + if (Segments.size()) { + startSection(SubSection, wasm::WASM_SEGMENT_INFO); + encodeULEB128(Segments.size(), getStream()); + for (const WasmDataSegment &Segment : Segments) { + writeString(Segment.Name); + encodeULEB128(Segment.Alignment, getStream()); + encodeULEB128(Segment.Flags, getStream()); + } + endSection(SubSection); + } + + if (!InitFuncs.empty()) { + startSection(SubSection, wasm::WASM_INIT_FUNCS); + encodeULEB128(InitFuncs.size(), getStream()); + for (auto &StartFunc : InitFuncs) { + encodeULEB128(StartFunc.first, getStream()); // priority + encodeULEB128(StartFunc.second, getStream()); // function index + } endSection(SubSection); } @@ -920,16 +966,9 @@ uint32_t WasmObjectWriter::registerFunctionType(const MCSymbolWasm& Symbol) { assert(Symbol.isFunction()); WasmFunctionType F; - if (Symbol.isVariable()) { - const MCExpr *Expr = Symbol.getVariableValue(); - auto *Inner = cast<MCSymbolRefExpr>(Expr); - const auto *ResolvedSym = cast<MCSymbolWasm>(&Inner->getSymbol()); - F.Returns = ResolvedSym->getReturns(); - F.Params = ResolvedSym->getParams(); - } else { - F.Returns = Symbol.getReturns(); - F.Params = Symbol.getParams(); - } + const MCSymbolWasm* ResolvedSym = ResolveSymbol(Symbol); + F.Returns = ResolvedSym->getReturns(); + F.Params = ResolvedSym->getParams(); auto Pair = FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size())); @@ -951,23 +990,20 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, // Collect information from the available symbols. SmallVector<WasmFunction, 4> Functions; SmallVector<uint32_t, 4> TableElems; - SmallVector<WasmGlobal, 4> Globals; SmallVector<WasmImport, 4> Imports; SmallVector<WasmExport, 4> Exports; - SmallVector<StringRef, 4> WeakSymbols; + SmallVector<std::pair<StringRef, uint32_t>, 4> SymbolFlags; + SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs; SmallPtrSet<const MCSymbolWasm *, 4> IsAddressTaken; unsigned NumFuncImports = 0; - unsigned NumGlobalImports = 0; - SmallVector<char, 0> DataBytes; - uint32_t DataAlignment = 1; - uint32_t StackPointerGlobal = 0; - bool HasStackPointer = false; + SmallVector<WasmDataSegment, 4> DataSegments; + uint32_t DataSize = 0; // Populate the IsAddressTaken set. for (const WasmRelocationEntry &RelEntry : CodeRelocations) { switch (RelEntry.Type) { case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: IsAddressTaken.insert(RelEntry.Symbol); break; default: @@ -977,7 +1013,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, for (const WasmRelocationEntry &RelEntry : DataRelocations) { switch (RelEntry.Type) { case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: IsAddressTaken.insert(RelEntry.Symbol); break; default: @@ -985,42 +1021,11 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, } } - // Populate the Imports set. - for (const MCSymbol &S : Asm.symbols()) { - const auto &WS = static_cast<const MCSymbolWasm &>(S); - - if (WS.isTemporary()) - continue; - - if (WS.isFunction()) - registerFunctionType(WS); - - // If the symbol is not defined in this translation unit, import it. - if (!WS.isDefined(/*SetUsed=*/false) || WS.isVariable()) { - WasmImport Import; - Import.ModuleName = WS.getModuleName(); - Import.FieldName = WS.getName(); - - if (WS.isFunction()) { - Import.Kind = wasm::WASM_EXTERNAL_FUNCTION; - Import.Type = getFunctionType(WS); - SymbolIndices[&WS] = NumFuncImports; - ++NumFuncImports; - } else { - Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; - Import.Type = int32_t(PtrType); - SymbolIndices[&WS] = NumGlobalImports; - ++NumGlobalImports; - } - - Imports.push_back(Import); - } - } - // In the special .global_variables section, we've encoded global // variables used by the function. Translate them into the Globals // list. - MCSectionWasm *GlobalVars = Ctx.getWasmSection(".global_variables", 0, 0); + MCSectionWasm *GlobalVars = + Ctx.getWasmSection(".global_variables", SectionKind::getMetadata()); if (!GlobalVars->getFragmentList().empty()) { if (GlobalVars->getFragmentList().size() != 1) report_fatal_error("only one .global_variables fragment supported"); @@ -1074,23 +1079,91 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, } } - // In the special .stack_pointer section, we've encoded the stack pointer - // index. - MCSectionWasm *StackPtr = Ctx.getWasmSection(".stack_pointer", 0, 0); - if (!StackPtr->getFragmentList().empty()) { - if (StackPtr->getFragmentList().size() != 1) - report_fatal_error("only one .stack_pointer fragment supported"); - const MCFragment &Frag = *StackPtr->begin(); - if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) - report_fatal_error("only data supported in .stack_pointer"); - const auto &DataFrag = cast<MCDataFragment>(Frag); - if (!DataFrag.getFixups().empty()) - report_fatal_error("fixups not supported in .stack_pointer"); - const SmallVectorImpl<char> &Contents = DataFrag.getContents(); - if (Contents.size() != 4) - report_fatal_error("only one entry supported in .stack_pointer"); - HasStackPointer = true; - StackPointerGlobal = NumGlobalImports + *(const int32_t *)Contents.data(); + // For now, always emit the memory import, since loads and stores are not + // valid without it. In the future, we could perhaps be more clever and omit + // it if there are no loads or stores. + MCSymbolWasm *MemorySym = + cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__linear_memory")); + WasmImport MemImport; + MemImport.ModuleName = MemorySym->getModuleName(); + MemImport.FieldName = MemorySym->getName(); + MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY; + Imports.push_back(MemImport); + + // For now, always emit the table section, since indirect calls are not + // valid without it. In the future, we could perhaps be more clever and omit + // it if there are no indirect calls. + MCSymbolWasm *TableSym = + cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__indirect_function_table")); + WasmImport TableImport; + TableImport.ModuleName = TableSym->getModuleName(); + TableImport.FieldName = TableSym->getName(); + TableImport.Kind = wasm::WASM_EXTERNAL_TABLE; + TableImport.Type = wasm::WASM_TYPE_ANYFUNC; + Imports.push_back(TableImport); + + // Populate FunctionTypeIndices and Imports. + for (const MCSymbol &S : Asm.symbols()) { + const auto &WS = static_cast<const MCSymbolWasm &>(S); + + // Register types for all functions, including those with private linkage + // (making them + // because wasm always needs a type signature. + if (WS.isFunction()) + registerFunctionType(WS); + + if (WS.isTemporary()) + continue; + + // If the symbol is not defined in this translation unit, import it. + if (!WS.isDefined(/*SetUsed=*/false)) { + WasmImport Import; + Import.ModuleName = WS.getModuleName(); + Import.FieldName = WS.getName(); + + if (WS.isFunction()) { + Import.Kind = wasm::WASM_EXTERNAL_FUNCTION; + Import.Type = getFunctionType(WS); + SymbolIndices[&WS] = NumFuncImports; + ++NumFuncImports; + } else { + Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; + Import.Type = int32_t(PtrType); + Import.IsMutable = false; + SymbolIndices[&WS] = NumGlobalImports; + + // If this global is the stack pointer, make it mutable and remember it + // so that we can emit metadata for it. + if (WS.getName() == "__stack_pointer") + Import.IsMutable = true; + + ++NumGlobalImports; + } + + Imports.push_back(Import); + } + } + + for (MCSection &Sec : Asm) { + auto &Section = static_cast<MCSectionWasm &>(Sec); + if (!Section.isWasmData()) + continue; + + // .init_array sections are handled specially elsewhere. + if (cast<MCSectionWasm>(Sec).getSectionName().startswith(".init_array")) + continue; + + DataSize = alignTo(DataSize, Section.getAlignment()); + DataSegments.emplace_back(); + WasmDataSegment &Segment = DataSegments.back(); + Segment.Name = Section.getSectionName(); + Segment.Offset = DataSize; + Segment.Section = &Section; + addData(Segment.Data, Section); + Segment.Alignment = Section.getAlignment(); + Segment.Flags = 0; + DataSize += Segment.Data.size(); + Section.setMemoryOffset(Segment.Offset); } // Handle regular defined and undefined symbols. @@ -1106,10 +1179,14 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, << S.isExternal() << " isTemporary=" << S.isTemporary() << " isFunction=" << WS.isFunction() << " isWeak=" << WS.isWeak() + << " isHidden=" << WS.isHidden() << " isVariable=" << WS.isVariable() << "\n"); - if (WS.isWeak()) - WeakSymbols.push_back(WS.getName()); + if (WS.isWeak() || WS.isHidden()) { + uint32_t Flags = (WS.isWeak() ? wasm::WASM_SYMBOL_BINDING_WEAK : 0) | + (WS.isHidden() ? wasm::WASM_SYMBOL_VISIBILITY_HIDDEN : 0); + SymbolFlags.emplace_back(WS.getName(), Flags); + } if (WS.isVariable()) continue; @@ -1155,9 +1232,6 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, if (!WS.isDefined(/*SetUsed=*/false)) continue; - if (WS.getOffset() != 0) - report_fatal_error("data sections must contain one variable each: " + - WS.getName()); if (!WS.getSize()) report_fatal_error("data symbols must have a size set with .size: " + WS.getName()); @@ -1166,49 +1240,16 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, if (!WS.getSize()->evaluateAsAbsolute(Size, Layout)) report_fatal_error(".size expression must be evaluatable"); - auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection()); - - if (uint64_t(Size) != Layout.getSectionFileSize(&DataSection)) - report_fatal_error("data sections must contain at most one variable"); - - DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); - DataAlignment = std::max(DataAlignment, DataSection.getAlignment()); - - DataSection.setSectionOffset(DataBytes.size()); - - for (const MCFragment &Frag : DataSection) { - if (Frag.hasInstructions()) - report_fatal_error("only data supported in data sections"); - - if (auto *Align = dyn_cast<MCAlignFragment>(&Frag)) { - if (Align->getValueSize() != 1) - 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()); - DataBytes.resize(Size, Value); - } else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) { - DataBytes.insert(DataBytes.end(), Fill->getSize(), Fill->getValue()); - } else { - const auto &DataFrag = cast<MCDataFragment>(Frag); - const SmallVectorImpl<char> &Contents = DataFrag.getContents(); - - DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); - } - } - // For each global, prepare a corresponding wasm global holding its // address. For externals these will also be named exports. Index = NumGlobalImports + Globals.size(); + auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection()); WasmGlobal Global; Global.Type = PtrType; Global.IsMutable = false; Global.HasImport = false; - Global.InitialValue = DataSection.getSectionOffset(); + Global.InitialValue = DataSection.getMemoryOffset() + Layout.getSymbolOffset(WS); Global.ImportIndex = 0; SymbolIndices[&WS] = Index; DEBUG(dbgs() << " -> global index: " << Index << "\n"); @@ -1216,7 +1257,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, } // If the symbol is visible outside this translation unit, export it. - if ((WS.isExternal() && WS.isDefined(/*SetUsed=*/false))) { + if (WS.isDefined(/*SetUsed=*/false)) { WasmExport Export; Export.FieldName = WS.getName(); Export.Index = Index; @@ -1226,6 +1267,8 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; DEBUG(dbgs() << " -> export " << Exports.size() << "\n"); Exports.push_back(Export); + if (!WS.isExternal()) + SymbolFlags.emplace_back(WS.getName(), wasm::WASM_SYMBOL_BINDING_LOCAL); } } @@ -1235,18 +1278,18 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, for (const MCSymbol &S : Asm.symbols()) { if (!S.isVariable()) continue; + assert(S.isDefined(/*SetUsed=*/false)); - const auto &WS = static_cast<const MCSymbolWasm &>(S); // Find the target symbol of this weak alias and export that index - const MCExpr *Expr = WS.getVariableValue(); - auto *Inner = cast<MCSymbolRefExpr>(Expr); - const auto *ResolvedSym = cast<MCSymbolWasm>(&Inner->getSymbol()); + const auto &WS = static_cast<const MCSymbolWasm &>(S); + const MCSymbolWasm *ResolvedSym = ResolveSymbol(WS); DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym << "'\n"); assert(SymbolIndices.count(ResolvedSym) > 0); uint32_t Index = SymbolIndices.find(ResolvedSym)->second; DEBUG(dbgs() << " -> index:" << Index << "\n"); + SymbolIndices[&WS] = Index; WasmExport Export; Export.FieldName = WS.getName(); Export.Index = Index; @@ -1256,6 +1299,9 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; DEBUG(dbgs() << " -> export " << Exports.size() << "\n"); Exports.push_back(Export); + + if (!WS.isExternal()) + SymbolFlags.emplace_back(WS.getName(), wasm::WASM_SYMBOL_BINDING_LOCAL); } // Add types for indirect function calls. @@ -1266,30 +1312,84 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, registerFunctionType(*Fixup.Symbol); } + // Translate .init_array section contents into start functions. + for (const MCSection &S : Asm) { + const auto &WS = static_cast<const MCSectionWasm &>(S); + if (WS.getSectionName().startswith(".fini_array")) + report_fatal_error(".fini_array sections are unsupported"); + if (!WS.getSectionName().startswith(".init_array")) + continue; + if (WS.getFragmentList().empty()) + continue; + if (WS.getFragmentList().size() != 2) + report_fatal_error("only one .init_array section fragment supported"); + const MCFragment &AlignFrag = *WS.begin(); + if (AlignFrag.getKind() != MCFragment::FT_Align) + report_fatal_error(".init_array section should be aligned"); + if (cast<MCAlignFragment>(AlignFrag).getAlignment() != (is64Bit() ? 8 : 4)) + report_fatal_error(".init_array section should be aligned for pointers"); + const MCFragment &Frag = *std::next(WS.begin()); + if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) + report_fatal_error("only data supported in .init_array section"); + uint16_t Priority = UINT16_MAX; + if (WS.getSectionName().size() != 11) { + if (WS.getSectionName()[11] != '.') + report_fatal_error(".init_array section priority should start with '.'"); + if (WS.getSectionName().substr(12).getAsInteger(10, Priority)) + report_fatal_error("invalid .init_array section priority"); + } + 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(); + 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)); + const MCExpr *Expr = Fixup.getValue(); + auto *Sym = dyn_cast<MCSymbolRefExpr>(Expr); + if (!Sym) + report_fatal_error("fixups in .init_array should be symbol references"); + if (Sym->getKind() != MCSymbolRefExpr::VK_WebAssembly_FUNCTION) + report_fatal_error("symbols in .init_array should be for functions"); + auto I = SymbolIndices.find(cast<MCSymbolWasm>(&Sym->getSymbol())); + if (I == SymbolIndices.end()) + report_fatal_error("symbols in .init_array should be defined"); + uint32_t Index = I->second; + InitFuncs.push_back(std::make_pair(Priority, Index)); + } + } + // Write out the Wasm header. writeHeader(Asm); writeTypeSection(FunctionTypes); - writeImportSection(Imports); + writeImportSection(Imports, DataSize, TableElems.size()); writeFunctionSection(Functions); - writeTableSection(TableElems.size()); - writeMemorySection(DataBytes); - writeGlobalSection(Globals); + // Skip the "table" section; we import the table instead. + // Skip the "memory" section; we import the memory instead. + writeGlobalSection(); writeExportSection(Exports); - // TODO: Start Section writeElemSection(TableElems); writeCodeSection(Asm, Layout, Functions); - uint64_t DataSectionHeaderSize = writeDataSection(DataBytes); + writeDataSection(DataSegments); writeNameSection(Functions, Imports, NumFuncImports); writeCodeRelocSection(); - writeDataRelocSection(DataSectionHeaderSize); - writeLinkingMetaDataSection(DataBytes.size(), DataAlignment, WeakSymbols, HasStackPointer, StackPointerGlobal); + writeDataRelocSection(); + writeLinkingMetaDataSection(DataSegments, DataSize, SymbolFlags, + InitFuncs); // TODO: Translate the .comment section to the output. // TODO: Translate debug sections to the output. } -MCObjectWriter *llvm::createWasmObjectWriter(MCWasmObjectTargetWriter *MOTW, - raw_pwrite_stream &OS) { - return new WasmObjectWriter(MOTW, OS); +std::unique_ptr<MCObjectWriter> +llvm::createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW, + raw_pwrite_stream &OS) { + // FIXME: Can't use make_unique<WasmObjectWriter>(...) as WasmObjectWriter's + // destructor is private. Is that necessary? + return std::unique_ptr<MCObjectWriter>( + new WasmObjectWriter(std::move(MOTW), OS)); } diff --git a/lib/MC/WinCOFFObjectWriter.cpp b/lib/MC/WinCOFFObjectWriter.cpp index 956ae70b38d1..9f1db46939c7 100644 --- a/lib/MC/WinCOFFObjectWriter.cpp +++ b/lib/MC/WinCOFFObjectWriter.cpp @@ -145,7 +145,8 @@ public: bool UseBigObj; - WinCOFFObjectWriter(MCWinCOFFObjectTargetWriter *MOTW, raw_pwrite_stream &OS); + WinCOFFObjectWriter(std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, + raw_pwrite_stream &OS); void reset() override { memset(&Header, 0, sizeof(Header)); @@ -222,9 +223,9 @@ void COFFSymbol::set_name_offset(uint32_t Offset) { //------------------------------------------------------------------------------ // WinCOFFObjectWriter class implementation -WinCOFFObjectWriter::WinCOFFObjectWriter(MCWinCOFFObjectTargetWriter *MOTW, - raw_pwrite_stream &OS) - : MCObjectWriter(OS, true), TargetObjectWriter(MOTW) { +WinCOFFObjectWriter::WinCOFFObjectWriter( + std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS) + : MCObjectWriter(OS, true), TargetObjectWriter(std::move(MOTW)) { Header.Machine = TargetObjectWriter->getMachine(); } @@ -1084,8 +1085,7 @@ void MCWinCOFFObjectTargetWriter::anchor() {} //------------------------------------------------------------------------------ // WinCOFFObjectWriter factory function -MCObjectWriter * -llvm::createWinCOFFObjectWriter(MCWinCOFFObjectTargetWriter *MOTW, - raw_pwrite_stream &OS) { - return new WinCOFFObjectWriter(MOTW, OS); +std::unique_ptr<MCObjectWriter> llvm::createWinCOFFObjectWriter( + std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS) { + return llvm::make_unique<WinCOFFObjectWriter>(std::move(MOTW), OS); } |