Index: head/contrib/llvm/include/llvm/MC/MCAssembler.h =================================================================== --- head/contrib/llvm/include/llvm/MC/MCAssembler.h (revision 331365) +++ head/contrib/llvm/include/llvm/MC/MCAssembler.h (revision 331366) @@ -1,443 +1,445 @@ //===- MCAssembler.h - Object File Generation -------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_MC_MCASSEMBLER_H #define LLVM_MC_MCASSEMBLER_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCFragment.h" #include "llvm/MC/MCLinkerOptimizationHint.h" #include "llvm/MC/MCSymbol.h" #include #include #include #include #include #include namespace llvm { class MCAsmBackend; class MCAsmLayout; class MCContext; class MCCodeEmitter; class MCFragment; class MCObjectWriter; class MCSection; class MCValue; // FIXME: This really doesn't belong here. See comments below. struct IndirectSymbolData { MCSymbol *Symbol; MCSection *Section; }; // FIXME: Ditto this. Purely so the Streamer and the ObjectWriter can talk // to one another. struct DataRegionData { // This enum should be kept in sync w/ the mach-o definition in // llvm/Object/MachOFormat.h. enum KindTy { Data = 1, JumpTable8, JumpTable16, JumpTable32 } Kind; MCSymbol *Start; MCSymbol *End; }; class MCAssembler { friend class MCAsmLayout; public: using SectionListType = std::vector; using SymbolDataListType = std::vector; using const_iterator = pointee_iterator; using iterator = pointee_iterator; using const_symbol_iterator = pointee_iterator; using symbol_iterator = pointee_iterator; using symbol_range = iterator_range; using const_symbol_range = iterator_range; using const_indirect_symbol_iterator = std::vector::const_iterator; using indirect_symbol_iterator = std::vector::iterator; using const_data_region_iterator = std::vector::const_iterator; using data_region_iterator = std::vector::iterator; /// MachO specific deployment target version info. // A Major version of 0 indicates that no version information was supplied // and so the corresponding load command should not be emitted. using VersionInfoType = struct { bool EmitBuildVersion; union { MCVersionMinType Type; ///< Used when EmitBuildVersion==false. MachO::PlatformType Platform; ///< Used when EmitBuildVersion==true. } TypeOrPlatform; unsigned Major; unsigned Minor; unsigned Update; }; private: MCContext &Context; MCAsmBackend &Backend; MCCodeEmitter &Emitter; MCObjectWriter &Writer; SectionListType Sections; SymbolDataListType Symbols; std::vector IndirectSymbols; std::vector DataRegions; /// The list of linker options to propagate into the object file. std::vector> LinkerOptions; /// List of declared file names std::vector FileNames; MCDwarfLineTableParams LTParams; /// The set of function symbols for which a .thumb_func directive has /// been seen. // // FIXME: We really would like this in target specific code rather than // here. Maybe when the relocation stuff moves to target specific, // this can go with it? The streamer would need some target specific // refactoring too. mutable SmallPtrSet ThumbFuncs; /// \brief The bundle alignment size currently set in the assembler. /// /// By default it's 0, which means bundling is disabled. unsigned BundleAlignSize; bool RelaxAll : 1; bool SubsectionsViaSymbols : 1; bool IncrementalLinkerCompatible : 1; /// ELF specific e_header flags // It would be good if there were an MCELFAssembler class to hold this. // ELF header flags are used both by the integrated and standalone assemblers. // Access to the flags is necessary in cases where assembler directives affect // which flags to be set. unsigned ELFHeaderEFlags; /// Used to communicate Linker Optimization Hint information between /// the Streamer and the .o writer MCLOHContainer LOHContainer; VersionInfoType VersionInfo; /// Evaluate a fixup to a relocatable expression and the value which should be /// placed into the fixup. /// /// \param Layout The layout to use for evaluation. /// \param Fixup The fixup to evaluate. /// \param DF The fragment the fixup is inside. /// \param Target [out] On return, the relocatable expression the fixup /// evaluates to. /// \param Value [out] On return, the value of the fixup as currently laid /// out. /// \return Whether the fixup value was fully resolved. This is true if the /// \p Value result is fixed, otherwise the value may change due to /// relocation. bool evaluateFixup(const MCAsmLayout &Layout, const MCFixup &Fixup, const MCFragment *DF, MCValue &Target, uint64_t &Value) const; /// Check whether a fixup can be satisfied, or whether it needs to be relaxed /// (increased in size, in order to hold its value correctly). bool fixupNeedsRelaxation(const MCFixup &Fixup, const MCRelaxableFragment *DF, const MCAsmLayout &Layout) const; /// Check whether the given fragment needs relaxation. bool fragmentNeedsRelaxation(const MCRelaxableFragment *IF, const MCAsmLayout &Layout) const; /// \brief Perform one layout iteration and return true if any offsets /// were adjusted. bool layoutOnce(MCAsmLayout &Layout); /// \brief Perform one layout iteration of the given section and return true /// if any offsets were adjusted. bool layoutSectionOnce(MCAsmLayout &Layout, MCSection &Sec); bool relaxInstruction(MCAsmLayout &Layout, MCRelaxableFragment &IF); bool relaxPaddingFragment(MCAsmLayout &Layout, MCPaddingFragment &PF); bool relaxLEB(MCAsmLayout &Layout, MCLEBFragment &IF); bool relaxDwarfLineAddr(MCAsmLayout &Layout, MCDwarfLineAddrFragment &DF); bool relaxDwarfCallFrameFragment(MCAsmLayout &Layout, MCDwarfCallFrameFragment &DF); bool relaxCVInlineLineTable(MCAsmLayout &Layout, MCCVInlineLineTableFragment &DF); bool relaxCVDefRange(MCAsmLayout &Layout, MCCVDefRangeFragment &DF); /// finishLayout - Finalize a layout, including fragment lowering. void finishLayout(MCAsmLayout &Layout); std::tuple handleFixup(const MCAsmLayout &Layout, MCFragment &F, const MCFixup &Fixup); public: + std::vector> Symvers; + /// Construct a new assembler instance. // // FIXME: How are we going to parameterize this? Two obvious options are stay // concrete and require clients to pass in a target like object. The other // option is to make this abstract, and have targets provide concrete // implementations as we do with AsmParser. MCAssembler(MCContext &Context, MCAsmBackend &Backend, MCCodeEmitter &Emitter, MCObjectWriter &Writer); MCAssembler(const MCAssembler &) = delete; MCAssembler &operator=(const MCAssembler &) = delete; ~MCAssembler(); /// Compute the effective fragment size assuming it is laid out at the given /// \p SectionAddress and \p FragmentOffset. uint64_t computeFragmentSize(const MCAsmLayout &Layout, const MCFragment &F) const; /// Find the symbol which defines the atom containing the given symbol, or /// null if there is no such symbol. const MCSymbol *getAtom(const MCSymbol &S) const; /// Check whether a particular symbol is visible to the linker and is required /// in the symbol table, or whether it can be discarded by the assembler. This /// also effects whether the assembler treats the label as potentially /// defining a separate atom. bool isSymbolLinkerVisible(const MCSymbol &SD) const; /// Emit the section contents using the given object writer. void writeSectionData(const MCSection *Section, const MCAsmLayout &Layout) const; /// Check whether a given symbol has been flagged with .thumb_func. bool isThumbFunc(const MCSymbol *Func) const; /// Flag a function symbol as the target of a .thumb_func directive. void setIsThumbFunc(const MCSymbol *Func) { ThumbFuncs.insert(Func); } /// ELF e_header flags unsigned getELFHeaderEFlags() const { return ELFHeaderEFlags; } void setELFHeaderEFlags(unsigned Flags) { ELFHeaderEFlags = Flags; } /// MachO deployment target version information. const VersionInfoType &getVersionInfo() const { return VersionInfo; } void setVersionMin(MCVersionMinType Type, unsigned Major, unsigned Minor, unsigned Update) { VersionInfo.EmitBuildVersion = false; VersionInfo.TypeOrPlatform.Type = Type; VersionInfo.Major = Major; VersionInfo.Minor = Minor; VersionInfo.Update = Update; } void setBuildVersion(MachO::PlatformType Platform, unsigned Major, unsigned Minor, unsigned Update) { VersionInfo.EmitBuildVersion = true; VersionInfo.TypeOrPlatform.Platform = Platform; VersionInfo.Major = Major; VersionInfo.Minor = Minor; VersionInfo.Update = Update; } /// Reuse an assembler instance /// void reset(); MCContext &getContext() const { return Context; } MCAsmBackend &getBackend() const { return Backend; } MCCodeEmitter &getEmitter() const { return Emitter; } MCObjectWriter &getWriter() const { return Writer; } MCDwarfLineTableParams getDWARFLinetableParams() const { return LTParams; } void setDWARFLinetableParams(MCDwarfLineTableParams P) { LTParams = P; } /// Finish - Do final processing and write the object to the output stream. /// \p Writer is used for custom object writer (as the MCJIT does), /// if not specified it is automatically created from backend. void Finish(); // Layout all section and prepare them for emission. void layout(MCAsmLayout &Layout); // FIXME: This does not belong here. bool getSubsectionsViaSymbols() const { return SubsectionsViaSymbols; } void setSubsectionsViaSymbols(bool Value) { SubsectionsViaSymbols = Value; } bool isIncrementalLinkerCompatible() const { return IncrementalLinkerCompatible; } void setIncrementalLinkerCompatible(bool Value) { IncrementalLinkerCompatible = Value; } bool getRelaxAll() const { return RelaxAll; } void setRelaxAll(bool Value) { RelaxAll = Value; } bool isBundlingEnabled() const { return BundleAlignSize != 0; } unsigned getBundleAlignSize() const { return BundleAlignSize; } void setBundleAlignSize(unsigned Size) { assert((Size == 0 || !(Size & (Size - 1))) && "Expect a power-of-two bundle align size"); BundleAlignSize = Size; } /// \name Section List Access /// @{ iterator begin() { return Sections.begin(); } const_iterator begin() const { return Sections.begin(); } iterator end() { return Sections.end(); } const_iterator end() const { return Sections.end(); } size_t size() const { return Sections.size(); } /// @} /// \name Symbol List Access /// @{ symbol_iterator symbol_begin() { return Symbols.begin(); } const_symbol_iterator symbol_begin() const { return Symbols.begin(); } symbol_iterator symbol_end() { return Symbols.end(); } const_symbol_iterator symbol_end() const { return Symbols.end(); } symbol_range symbols() { return make_range(symbol_begin(), symbol_end()); } const_symbol_range symbols() const { return make_range(symbol_begin(), symbol_end()); } size_t symbol_size() const { return Symbols.size(); } /// @} /// \name Indirect Symbol List Access /// @{ // FIXME: This is a total hack, this should not be here. Once things are // factored so that the streamer has direct access to the .o writer, it can // disappear. std::vector &getIndirectSymbols() { return IndirectSymbols; } indirect_symbol_iterator indirect_symbol_begin() { return IndirectSymbols.begin(); } const_indirect_symbol_iterator indirect_symbol_begin() const { return IndirectSymbols.begin(); } indirect_symbol_iterator indirect_symbol_end() { return IndirectSymbols.end(); } const_indirect_symbol_iterator indirect_symbol_end() const { return IndirectSymbols.end(); } size_t indirect_symbol_size() const { return IndirectSymbols.size(); } /// @} /// \name Linker Option List Access /// @{ std::vector> &getLinkerOptions() { return LinkerOptions; } /// @} /// \name Data Region List Access /// @{ // FIXME: This is a total hack, this should not be here. Once things are // factored so that the streamer has direct access to the .o writer, it can // disappear. std::vector &getDataRegions() { return DataRegions; } data_region_iterator data_region_begin() { return DataRegions.begin(); } const_data_region_iterator data_region_begin() const { return DataRegions.begin(); } data_region_iterator data_region_end() { return DataRegions.end(); } const_data_region_iterator data_region_end() const { return DataRegions.end(); } size_t data_region_size() const { return DataRegions.size(); } /// @} /// \name Data Region List Access /// @{ // FIXME: This is a total hack, this should not be here. Once things are // factored so that the streamer has direct access to the .o writer, it can // disappear. MCLOHContainer &getLOHContainer() { return LOHContainer; } const MCLOHContainer &getLOHContainer() const { return const_cast(this)->getLOHContainer(); } /// @} /// \name Backend Data Access /// @{ bool registerSection(MCSection &Section); void registerSymbol(const MCSymbol &Symbol, bool *Created = nullptr); ArrayRef getFileNames() { return FileNames; } void addFileName(StringRef FileName) { if (!is_contained(FileNames, FileName)) FileNames.push_back(FileName); } /// \brief Write the necessary bundle padding to the given object writer. /// Expects a fragment \p F containing instructions and its size \p FSize. void writeFragmentPadding(const MCFragment &F, uint64_t FSize, MCObjectWriter *OW) const; /// @} void dump() const; }; /// \brief Compute the amount of padding required before the fragment \p F to /// obey bundling restrictions, where \p FOffset is the fragment's offset in /// its section and \p FSize is the fragment's size. uint64_t computeBundlePadding(const MCAssembler &Assembler, const MCFragment *F, uint64_t FOffset, uint64_t FSize); } // end namespace llvm #endif // LLVM_MC_MCASSEMBLER_H Index: head/contrib/llvm/include/llvm/MC/MCELFStreamer.h =================================================================== --- head/contrib/llvm/include/llvm/MC/MCELFStreamer.h (revision 331365) +++ head/contrib/llvm/include/llvm/MC/MCELFStreamer.h (revision 331366) @@ -1,100 +1,102 @@ //===- MCELFStreamer.h - MCStreamer ELF Object File Interface ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_MC_MCELFSTREAMER_H #define LLVM_MC_MCELFSTREAMER_H #include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCObjectStreamer.h" namespace llvm { class MCAsmBackend; class MCCodeEmitter; class MCExpr; class MCInst; class MCELFStreamer : public MCObjectStreamer { public: MCELFStreamer(MCContext &Context, std::unique_ptr TAB, raw_pwrite_stream &OS, std::unique_ptr Emitter); ~MCELFStreamer() override = default; /// state management void reset() override { SeenIdent = false; BundleGroups.clear(); MCObjectStreamer::reset(); } /// \name MCStreamer Interface /// @{ void InitSections(bool NoExecStack) override; void ChangeSection(MCSection *Section, const MCExpr *Subsection) override; void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override; void EmitLabel(MCSymbol *Symbol, SMLoc Loc, MCFragment *F) override; void EmitAssemblerFlag(MCAssemblerFlag Flag) override; void EmitThumbFunc(MCSymbol *Func) override; void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override; bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; + void emitELFSymverDirective(StringRef AliasName, + const MCSymbol *Aliasee) override; void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, uint64_t Size = 0, unsigned ByteAlignment = 0) override; void EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment = 0) override; void EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc = SMLoc()) override; void EmitIdent(StringRef IdentString) override; void EmitValueToAlignment(unsigned, int64_t, unsigned, unsigned) override; void FinishImpl() override; void EmitBundleAlignMode(unsigned AlignPow2) override; void EmitBundleLock(bool AlignToEnd) override; void EmitBundleUnlock() override; private: bool isBundleLocked() const; void EmitInstToFragment(const MCInst &Inst, const MCSubtargetInfo &) override; void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override; void fixSymbolsInTLSFixups(const MCExpr *expr); /// \brief Merge the content of the fragment \p EF into the fragment \p DF. void mergeFragment(MCDataFragment *, MCDataFragment *); bool SeenIdent = false; /// BundleGroups - The stack of fragments holding the bundle-locked /// instructions. SmallVector BundleGroups; }; MCELFStreamer *createARMELFStreamer(MCContext &Context, std::unique_ptr TAB, raw_pwrite_stream &OS, std::unique_ptr Emitter, bool RelaxAll, bool IsThumb); } // end namespace llvm #endif // LLVM_MC_MCELFSTREAMER_H Index: head/contrib/llvm/include/llvm/MC/MCStreamer.h =================================================================== --- head/contrib/llvm/include/llvm/MC/MCStreamer.h (revision 331365) +++ head/contrib/llvm/include/llvm/MC/MCStreamer.h (revision 331366) @@ -1,947 +1,948 @@ //===- MCStreamer.h - High-level Streaming Machine Code Output --*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file declares the MCStreamer class. // //===----------------------------------------------------------------------===// #ifndef LLVM_MC_MCSTREAMER_H #define LLVM_MC_MCSTREAMER_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCLinkerOptimizationHint.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCWinEH.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/TargetParser.h" #include #include #include #include #include #include namespace llvm { class AssemblerConstantPools; class formatted_raw_ostream; class MCAsmBackend; class MCCodeEmitter; struct MCCodePaddingContext; class MCContext; class MCExpr; class MCInst; class MCInstPrinter; class MCSection; class MCStreamer; class MCSymbolRefExpr; class MCSubtargetInfo; class raw_ostream; class Twine; using MCSectionSubPair = std::pair; /// Target specific streamer interface. This is used so that targets can /// implement support for target specific assembly directives. /// /// If target foo wants to use this, it should implement 3 classes: /// * FooTargetStreamer : public MCTargetStreamer /// * FooTargetAsmStreamer : public FooTargetStreamer /// * FooTargetELFStreamer : public FooTargetStreamer /// /// FooTargetStreamer should have a pure virtual method for each directive. For /// example, for a ".bar symbol_name" directive, it should have /// virtual emitBar(const MCSymbol &Symbol) = 0; /// /// The FooTargetAsmStreamer and FooTargetELFStreamer classes implement the /// method. The assembly streamer just prints ".bar symbol_name". The object /// streamer does whatever is needed to implement .bar in the object file. /// /// In the assembly printer and parser the target streamer can be used by /// calling getTargetStreamer and casting it to FooTargetStreamer: /// /// MCTargetStreamer &TS = OutStreamer.getTargetStreamer(); /// FooTargetStreamer &ATS = static_cast(TS); /// /// The base classes FooTargetAsmStreamer and FooTargetELFStreamer should /// *never* be treated differently. Callers should always talk to a /// FooTargetStreamer. class MCTargetStreamer { protected: MCStreamer &Streamer; public: MCTargetStreamer(MCStreamer &S); virtual ~MCTargetStreamer(); MCStreamer &getStreamer() { return Streamer; } // Allow a target to add behavior to the EmitLabel of MCStreamer. virtual void emitLabel(MCSymbol *Symbol); // Allow a target to add behavior to the emitAssignment of MCStreamer. virtual void emitAssignment(MCSymbol *Symbol, const MCExpr *Value); virtual void prettyPrintAsm(MCInstPrinter &InstPrinter, raw_ostream &OS, const MCInst &Inst, const MCSubtargetInfo &STI); virtual void emitDwarfFileDirective(StringRef Directive); /// Update streamer for a new active section. /// /// This is called by PopSection and SwitchSection, if the current /// section changes. virtual void changeSection(const MCSection *CurSection, MCSection *Section, const MCExpr *SubSection, raw_ostream &OS); virtual void emitValue(const MCExpr *Value); virtual void finish(); }; // FIXME: declared here because it is used from // lib/CodeGen/AsmPrinter/ARMException.cpp. class ARMTargetStreamer : public MCTargetStreamer { public: ARMTargetStreamer(MCStreamer &S); ~ARMTargetStreamer() override; virtual void emitFnStart(); virtual void emitFnEnd(); virtual void emitCantUnwind(); virtual void emitPersonality(const MCSymbol *Personality); virtual void emitPersonalityIndex(unsigned Index); virtual void emitHandlerData(); virtual void emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset = 0); virtual void emitMovSP(unsigned Reg, int64_t Offset = 0); virtual void emitPad(int64_t Offset); virtual void emitRegSave(const SmallVectorImpl &RegList, bool isVector); virtual void emitUnwindRaw(int64_t StackOffset, const SmallVectorImpl &Opcodes); virtual void switchVendor(StringRef Vendor); virtual void emitAttribute(unsigned Attribute, unsigned Value); virtual void emitTextAttribute(unsigned Attribute, StringRef String); virtual void emitIntTextAttribute(unsigned Attribute, unsigned IntValue, StringRef StringValue = ""); virtual void emitFPU(unsigned FPU); virtual void emitArch(ARM::ArchKind Arch); virtual void emitArchExtension(unsigned ArchExt); virtual void emitObjectArch(ARM::ArchKind Arch); void emitTargetAttributes(const MCSubtargetInfo &STI); virtual void finishAttributeSection(); virtual void emitInst(uint32_t Inst, char Suffix = '\0'); virtual void AnnotateTLSDescriptorSequence(const MCSymbolRefExpr *SRE); virtual void emitThumbSet(MCSymbol *Symbol, const MCExpr *Value); void finish() override; /// Reset any state between object emissions, i.e. the equivalent of /// MCStreamer's reset method. virtual void reset(); /// Callback used to implement the ldr= pseudo. /// Add a new entry to the constant pool for the current section and return an /// MCExpr that can be used to refer to the constant pool location. const MCExpr *addConstantPoolEntry(const MCExpr *, SMLoc Loc); /// Callback used to implemnt the .ltorg directive. /// Emit contents of constant pool for the current section. void emitCurrentConstantPool(); private: std::unique_ptr ConstantPools; }; /// \brief Streaming machine code generation interface. /// /// This interface is intended to provide a programatic interface that is very /// similar to the level that an assembler .s file provides. It has callbacks /// to emit bytes, handle directives, etc. The implementation of this interface /// retains state to know what the current section is etc. /// /// There are multiple implementations of this interface: one for writing out /// a .s file, and implementations that write out .o files of various formats. /// class MCStreamer { MCContext &Context; std::unique_ptr TargetStreamer; std::vector DwarfFrameInfos; MCDwarfFrameInfo *getCurrentDwarfFrameInfo(); /// Similar to DwarfFrameInfos, but for SEH unwind info. Chained frames may /// refer to each other, so use std::unique_ptr to provide pointer stability. std::vector> WinFrameInfos; WinEH::FrameInfo *CurrentWinFrameInfo; /// Retreive the current frame info if one is available and it is not yet /// closed. Otherwise, issue an error and return null. WinEH::FrameInfo *EnsureValidWinFrameInfo(SMLoc Loc); /// \brief Tracks an index to represent the order a symbol was emitted in. /// Zero means we did not emit that symbol. DenseMap SymbolOrdering; /// \brief This is stack of current and previous section values saved by /// PushSection. SmallVector, 4> SectionStack; /// The next unique ID to use when creating a WinCFI-related section (.pdata /// or .xdata). This ID ensures that we have a one-to-one mapping from /// code section to unwind info section, which MSVC's incremental linker /// requires. unsigned NextWinCFIID = 0; protected: MCStreamer(MCContext &Ctx); virtual void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame); virtual void EmitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame); /// When emitting an object file, create and emit a real label. When emitting /// textual assembly, this should do nothing to avoid polluting our output. virtual MCSymbol *EmitCFILabel(); WinEH::FrameInfo *getCurrentWinFrameInfo() { return CurrentWinFrameInfo; } virtual void EmitWindowsUnwindTables(); virtual void EmitRawTextImpl(StringRef String); public: MCStreamer(const MCStreamer &) = delete; MCStreamer &operator=(const MCStreamer &) = delete; virtual ~MCStreamer(); void visitUsedExpr(const MCExpr &Expr); virtual void visitUsedSymbol(const MCSymbol &Sym); void setTargetStreamer(MCTargetStreamer *TS) { TargetStreamer.reset(TS); } /// State management /// virtual void reset(); MCContext &getContext() const { return Context; } MCTargetStreamer *getTargetStreamer() { return TargetStreamer.get(); } unsigned getNumFrameInfos() { return DwarfFrameInfos.size(); } ArrayRef getDwarfFrameInfos() const { return DwarfFrameInfos; } bool hasUnfinishedDwarfFrameInfo(); unsigned getNumWinFrameInfos() { return WinFrameInfos.size(); } ArrayRef> getWinFrameInfos() const { return WinFrameInfos; } void generateCompactUnwindEncodings(MCAsmBackend *MAB); /// \name Assembly File Formatting. /// @{ /// \brief Return true if this streamer supports verbose assembly and if it is /// enabled. virtual bool isVerboseAsm() const { return false; } /// \brief Return true if this asm streamer supports emitting unformatted text /// to the .s file with EmitRawText. virtual bool hasRawTextSupport() const { return false; } /// \brief Is the integrated assembler required for this streamer to function /// correctly? virtual bool isIntegratedAssemblerRequired() const { return false; } /// \brief Add a textual comment. /// /// Typically for comments that can be emitted to the generated .s /// file if applicable as a QoI issue to make the output of the compiler /// more readable. This only affects the MCAsmStreamer, and only when /// verbose assembly output is enabled. /// /// If the comment includes embedded \n's, they will each get the comment /// prefix as appropriate. The added comment should not end with a \n. /// By default, each comment is terminated with an end of line, i.e. the /// EOL param is set to true by default. If one prefers not to end the /// comment with a new line then the EOL param should be passed /// with a false value. virtual void AddComment(const Twine &T, bool EOL = true) {} /// \brief Return a raw_ostream that comments can be written to. Unlike /// AddComment, you are required to terminate comments with \n if you use this /// method. virtual raw_ostream &GetCommentOS(); /// \brief Print T and prefix it with the comment string (normally #) and /// optionally a tab. This prints the comment immediately, not at the end of /// the current line. It is basically a safe version of EmitRawText: since it /// only prints comments, the object streamer ignores it instead of asserting. virtual void emitRawComment(const Twine &T, bool TabPrefix = true); /// \brief Add explicit comment T. T is required to be a valid /// comment in the output and does not need to be escaped. virtual void addExplicitComment(const Twine &T); /// \brief Emit added explicit comments. virtual void emitExplicitComments(); /// AddBlankLine - Emit a blank line to a .s file to pretty it up. virtual void AddBlankLine() {} /// @} /// \name Symbol & Section Management /// @{ /// \brief Return the current section that the streamer is emitting code to. MCSectionSubPair getCurrentSection() const { if (!SectionStack.empty()) return SectionStack.back().first; return MCSectionSubPair(); } MCSection *getCurrentSectionOnly() const { return getCurrentSection().first; } /// \brief Return the previous section that the streamer is emitting code to. MCSectionSubPair getPreviousSection() const { if (!SectionStack.empty()) return SectionStack.back().second; return MCSectionSubPair(); } /// \brief Returns an index to represent the order a symbol was emitted in. /// (zero if we did not emit that symbol) unsigned GetSymbolOrder(const MCSymbol *Sym) const { return SymbolOrdering.lookup(Sym); } /// \brief Update streamer for a new active section. /// /// This is called by PopSection and SwitchSection, if the current /// section changes. virtual void ChangeSection(MCSection *, const MCExpr *); /// \brief Save the current and previous section on the section stack. void PushSection() { SectionStack.push_back( std::make_pair(getCurrentSection(), getPreviousSection())); } /// \brief Restore the current and previous section from the section stack. /// Calls ChangeSection as needed. /// /// Returns false if the stack was empty. bool PopSection() { if (SectionStack.size() <= 1) return false; auto I = SectionStack.end(); --I; MCSectionSubPair OldSection = I->first; --I; MCSectionSubPair NewSection = I->first; if (OldSection != NewSection) ChangeSection(NewSection.first, NewSection.second); SectionStack.pop_back(); return true; } bool SubSection(const MCExpr *Subsection) { if (SectionStack.empty()) return false; SwitchSection(SectionStack.back().first.first, Subsection); return true; } /// Set the current section where code is being emitted to \p Section. This /// is required to update CurSection. /// /// This corresponds to assembler directives like .section, .text, etc. virtual void SwitchSection(MCSection *Section, const MCExpr *Subsection = nullptr); /// \brief Set the current section where code is being emitted to \p Section. /// This is required to update CurSection. This version does not call /// ChangeSection. void SwitchSectionNoChange(MCSection *Section, const MCExpr *Subsection = nullptr) { assert(Section && "Cannot switch to a null section!"); MCSectionSubPair curSection = SectionStack.back().first; SectionStack.back().second = curSection; if (MCSectionSubPair(Section, Subsection) != curSection) SectionStack.back().first = MCSectionSubPair(Section, Subsection); } /// \brief Create the default sections and set the initial one. virtual void InitSections(bool NoExecStack); MCSymbol *endSection(MCSection *Section); /// \brief Sets the symbol's section. /// /// Each emitted symbol will be tracked in the ordering table, /// so we can sort on them later. void AssignFragment(MCSymbol *Symbol, MCFragment *Fragment); /// \brief Emit a label for \p Symbol into the current section. /// /// This corresponds to an assembler statement such as: /// foo: /// /// \param Symbol - The symbol to emit. A given symbol should only be /// emitted as a label once, and symbols emitted as a label should never be /// used in an assignment. // FIXME: These emission are non-const because we mutate the symbol to // add the section we're emitting it to later. virtual void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()); virtual void EmitEHSymAttributes(const MCSymbol *Symbol, MCSymbol *EHSymbol); /// \brief Note in the output the specified \p Flag. virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); /// \brief Emit the given list \p Options of strings as linker /// options into the output. virtual void EmitLinkerOptions(ArrayRef Kind) {} /// \brief Note in the output the specified region \p Kind. virtual void EmitDataRegion(MCDataRegionType Kind) {} /// \brief Specify the Mach-O minimum deployment target version. virtual void EmitVersionMin(MCVersionMinType Type, unsigned Major, unsigned Minor, unsigned Update) {} /// Emit/Specify Mach-O build version command. /// \p Platform should be one of MachO::PlatformType. virtual void EmitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor, unsigned Update) {} void EmitVersionForTarget(const Triple &Target); /// \brief Note in the output that the specified \p Func is a Thumb mode /// function (ARM target only). virtual void EmitThumbFunc(MCSymbol *Func); /// \brief Emit an assignment of \p Value to \p Symbol. /// /// This corresponds to an assembler statement such as: /// symbol = value /// /// The assignment generates no code, but has the side effect of binding the /// value in the current context. For the assembly streamer, this prints the /// binding into the .s file. /// /// \param Symbol - The symbol being assigned to. /// \param Value - The value for the symbol. virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); /// \brief Emit an weak reference from \p Alias to \p Symbol. /// /// This corresponds to an assembler statement such as: /// .weakref alias, symbol /// /// \param Alias - The alias that is being created. /// \param Symbol - The symbol being aliased. virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); /// \brief Add the given \p Attribute to \p Symbol. virtual bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) = 0; /// \brief Set the \p DescValue for the \p Symbol. /// /// \param Symbol - The symbol to have its n_desc field set. /// \param DescValue - The value to set into the n_desc field. virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); /// \brief Start emitting COFF symbol definition /// /// \param Symbol - The symbol to have its External & Type fields set. virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol); /// \brief Emit the storage class of the symbol. /// /// \param StorageClass - The storage class the symbol should have. virtual void EmitCOFFSymbolStorageClass(int StorageClass); /// \brief Emit the type of the symbol. /// /// \param Type - A COFF type identifier (see COFF::SymbolType in X86COFF.h) virtual void EmitCOFFSymbolType(int Type); /// \brief Marks the end of the symbol definition. virtual void EndCOFFSymbolDef(); virtual void EmitCOFFSafeSEH(MCSymbol const *Symbol); /// \brief Emits a COFF section index. /// /// \param Symbol - Symbol the section number relocation should point to. virtual void EmitCOFFSectionIndex(MCSymbol const *Symbol); /// \brief Emits a COFF section relative relocation. /// /// \param Symbol - Symbol the section relative relocation should point to. virtual void EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset); /// \brief Emit an ELF .size directive. /// /// This corresponds to an assembler statement such as: /// .size symbol, expression virtual void emitELFSize(MCSymbol *Symbol, const MCExpr *Value); /// \brief Emit an ELF .symver directive. /// /// This corresponds to an assembler statement such as: /// .symver _start, foo@@SOME_VERSION - /// \param Alias - The versioned alias (i.e. "foo@@SOME_VERSION") + /// \param AliasName - The versioned alias (i.e. "foo@@SOME_VERSION") /// \param Aliasee - The aliased symbol (i.e. "_start") - virtual void emitELFSymverDirective(MCSymbol *Alias, const MCSymbol *Aliasee); + virtual void emitELFSymverDirective(StringRef AliasName, + const MCSymbol *Aliasee); /// \brief Emit a Linker Optimization Hint (LOH) directive. /// \param Args - Arguments of the LOH. virtual void EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) {} /// \brief Emit a common symbol. /// /// \param Symbol - The common symbol to emit. /// \param Size - The size of the common symbol. /// \param ByteAlignment - The alignment of the symbol if /// non-zero. This must be a power of 2. virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) = 0; /// \brief Emit a local common (.lcomm) symbol. /// /// \param Symbol - The common symbol to emit. /// \param Size - The size of the common symbol. /// \param ByteAlignment - The alignment of the common symbol in bytes. virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment); /// \brief Emit the zerofill section and an optional symbol. /// /// \param Section - The zerofill section to create and or to put the symbol /// \param Symbol - The zerofill symbol to emit, if non-NULL. /// \param Size - The size of the zerofill symbol. /// \param ByteAlignment - The alignment of the zerofill symbol if /// non-zero. This must be a power of 2 on some targets. virtual void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, uint64_t Size = 0, unsigned ByteAlignment = 0) = 0; /// \brief Emit a thread local bss (.tbss) symbol. /// /// \param Section - The thread local common section. /// \param Symbol - The thread local common symbol to emit. /// \param Size - The size of the symbol. /// \param ByteAlignment - The alignment of the thread local common symbol /// if non-zero. This must be a power of 2 on some targets. virtual void EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment = 0); /// @} /// \name Generating Data /// @{ /// \brief Emit the bytes in \p Data into the output. /// /// This is used to implement assembler directives such as .byte, .ascii, /// etc. virtual void EmitBytes(StringRef Data); /// Functionally identical to EmitBytes. When emitting textual assembly, this /// method uses .byte directives instead of .ascii or .asciz for readability. virtual void EmitBinaryData(StringRef Data); /// \brief Emit the expression \p Value into the output as a native /// integer of the given \p Size bytes. /// /// This is used to implement assembler directives such as .word, .quad, /// etc. /// /// \param Value - The value to emit. /// \param Size - The size of the integer (in bytes) to emit. This must /// match a native machine width. /// \param Loc - The location of the expression for error reporting. virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc = SMLoc()); void EmitValue(const MCExpr *Value, unsigned Size, SMLoc Loc = SMLoc()); /// \brief Special case of EmitValue that avoids the client having /// to pass in a MCExpr for constant integers. virtual void EmitIntValue(uint64_t Value, unsigned Size); virtual void EmitULEB128Value(const MCExpr *Value); virtual void EmitSLEB128Value(const MCExpr *Value); /// \brief Special case of EmitULEB128Value that avoids the client having to /// pass in a MCExpr for constant integers. void EmitULEB128IntValue(uint64_t Value); /// \brief Like EmitULEB128Value but pads the output to specific number of /// bytes. void EmitPaddedULEB128IntValue(uint64_t Value, unsigned PadTo); /// \brief Special case of EmitSLEB128Value that avoids the client having to /// pass in a MCExpr for constant integers. void EmitSLEB128IntValue(int64_t Value); /// \brief Special case of EmitValue that avoids the client having to pass in /// a MCExpr for MCSymbols. void EmitSymbolValue(const MCSymbol *Sym, unsigned Size, bool IsSectionRelative = false); /// \brief Emit the expression \p Value into the output as a dtprel /// (64-bit DTP relative) value. /// /// This is used to implement assembler directives such as .dtpreldword on /// targets that support them. virtual void EmitDTPRel64Value(const MCExpr *Value); /// \brief Emit the expression \p Value into the output as a dtprel /// (32-bit DTP relative) value. /// /// This is used to implement assembler directives such as .dtprelword on /// targets that support them. virtual void EmitDTPRel32Value(const MCExpr *Value); /// \brief Emit the expression \p Value into the output as a tprel /// (64-bit TP relative) value. /// /// This is used to implement assembler directives such as .tpreldword on /// targets that support them. virtual void EmitTPRel64Value(const MCExpr *Value); /// \brief Emit the expression \p Value into the output as a tprel /// (32-bit TP relative) value. /// /// This is used to implement assembler directives such as .tprelword on /// targets that support them. virtual void EmitTPRel32Value(const MCExpr *Value); /// \brief Emit the expression \p Value into the output as a gprel64 (64-bit /// GP relative) value. /// /// This is used to implement assembler directives such as .gpdword on /// targets that support them. virtual void EmitGPRel64Value(const MCExpr *Value); /// \brief Emit the expression \p Value into the output as a gprel32 (32-bit /// GP relative) value. /// /// This is used to implement assembler directives such as .gprel32 on /// targets that support them. virtual void EmitGPRel32Value(const MCExpr *Value); /// \brief Emit NumBytes bytes worth of the value specified by FillValue. /// This implements directives such as '.space'. void emitFill(uint64_t NumBytes, uint8_t FillValue); /// \brief Emit \p Size bytes worth of the value specified by \p FillValue. /// /// This is used to implement assembler directives such as .space or .skip. /// /// \param NumBytes - The number of bytes to emit. /// \param FillValue - The value to use when filling bytes. /// \param Loc - The location of the expression for error reporting. virtual void emitFill(const MCExpr &NumBytes, uint64_t FillValue, SMLoc Loc = SMLoc()); /// \brief Emit \p NumValues copies of \p Size bytes. Each \p Size bytes is /// taken from the lowest order 4 bytes of \p Expr expression. /// /// This is used to implement assembler directives such as .fill. /// /// \param NumValues - The number of copies of \p Size bytes to emit. /// \param Size - The size (in bytes) of each repeated value. /// \param Expr - The expression from which \p Size bytes are used. virtual void emitFill(uint64_t NumValues, int64_t Size, int64_t Expr); virtual void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, SMLoc Loc = SMLoc()); /// \brief Emit NumBytes worth of zeros. /// This function properly handles data in virtual sections. void EmitZeros(uint64_t NumBytes); /// \brief Emit some number of copies of \p Value until the byte alignment \p /// ByteAlignment is reached. /// /// If the number of bytes need to emit for the alignment is not a multiple /// of \p ValueSize, then the contents of the emitted fill bytes is /// undefined. /// /// This used to implement the .align assembler directive. /// /// \param ByteAlignment - The alignment to reach. This must be a power of /// two on some targets. /// \param Value - The value to use when filling bytes. /// \param ValueSize - The size of the integer (in bytes) to emit for /// \p Value. This must match a native machine width. /// \param MaxBytesToEmit - The maximum numbers of bytes to emit, or 0. If /// the alignment cannot be reached in this many bytes, no bytes are /// emitted. virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, unsigned ValueSize = 1, unsigned MaxBytesToEmit = 0); /// \brief Emit nops until the byte alignment \p ByteAlignment is reached. /// /// This used to align code where the alignment bytes may be executed. This /// can emit different bytes for different sizes to optimize execution. /// /// \param ByteAlignment - The alignment to reach. This must be a power of /// two on some targets. /// \param MaxBytesToEmit - The maximum numbers of bytes to emit, or 0. If /// the alignment cannot be reached in this many bytes, no bytes are /// emitted. virtual void EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit = 0); /// \brief Emit some number of copies of \p Value until the byte offset \p /// Offset is reached. /// /// This is used to implement assembler directives such as .org. /// /// \param Offset - The offset to reach. This may be an expression, but the /// expression must be associated with the current section. /// \param Value - The value to use when filling bytes. virtual void emitValueToOffset(const MCExpr *Offset, unsigned char Value, SMLoc Loc); virtual void EmitCodePaddingBasicBlockStart(const MCCodePaddingContext &Context) {} virtual void EmitCodePaddingBasicBlockEnd(const MCCodePaddingContext &Context) {} /// @} /// \brief Switch to a new logical file. This is used to implement the '.file /// "foo.c"' assembler directive. virtual void EmitFileDirective(StringRef Filename); /// \brief Emit the "identifiers" directive. This implements the /// '.ident "version foo"' assembler directive. virtual void EmitIdent(StringRef IdentString) {} /// \brief Associate a filename with a specified logical file number. This /// implements the DWARF2 '.file 4 "foo.c"' assembler directive. virtual unsigned EmitDwarfFileDirective(unsigned FileNo, StringRef Directory, StringRef Filename, unsigned CUID = 0); /// \brief This implements the DWARF2 '.loc fileno lineno ...' assembler /// directive. virtual void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column, unsigned Flags, unsigned Isa, unsigned Discriminator, StringRef FileName); /// Associate a filename with a specified logical file number, and also /// specify that file's checksum information. This implements the '.cv_file 4 /// "foo.c"' assembler directive. Returns true on success. virtual bool EmitCVFileDirective(unsigned FileNo, StringRef Filename, ArrayRef Checksum, unsigned ChecksumKind); /// \brief Introduces a function id for use with .cv_loc. virtual bool EmitCVFuncIdDirective(unsigned FunctionId); /// \brief Introduces an inline call site id for use with .cv_loc. Includes /// extra information for inline line table generation. virtual bool EmitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc, unsigned IAFile, unsigned IALine, unsigned IACol, SMLoc Loc); /// \brief This implements the CodeView '.cv_loc' assembler directive. virtual void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt, StringRef FileName, SMLoc Loc); /// \brief This implements the CodeView '.cv_linetable' assembler directive. virtual void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart, const MCSymbol *FnEnd); /// \brief This implements the CodeView '.cv_inline_linetable' assembler /// directive. virtual void EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, const MCSymbol *FnStartSym, const MCSymbol *FnEndSym); /// \brief This implements the CodeView '.cv_def_range' assembler /// directive. virtual void EmitCVDefRangeDirective( ArrayRef> Ranges, StringRef FixedSizePortion); /// \brief This implements the CodeView '.cv_stringtable' assembler directive. virtual void EmitCVStringTableDirective() {} /// \brief This implements the CodeView '.cv_filechecksums' assembler directive. virtual void EmitCVFileChecksumsDirective() {} /// This implements the CodeView '.cv_filechecksumoffset' assembler /// directive. virtual void EmitCVFileChecksumOffsetDirective(unsigned FileNo) {} /// This implements the CodeView '.cv_fpo_data' assembler directive. virtual void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc Loc = {}) {} /// Emit the absolute difference between two symbols. /// /// \pre Offset of \c Hi is greater than the offset \c Lo. virtual void emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size); virtual MCSymbol *getDwarfLineTableSymbol(unsigned CUID); virtual void EmitCFISections(bool EH, bool Debug); void EmitCFIStartProc(bool IsSimple); void EmitCFIEndProc(); virtual void EmitCFIDefCfa(int64_t Register, int64_t Offset); virtual void EmitCFIDefCfaOffset(int64_t Offset); virtual void EmitCFIDefCfaRegister(int64_t Register); virtual void EmitCFIOffset(int64_t Register, int64_t Offset); virtual void EmitCFIPersonality(const MCSymbol *Sym, unsigned Encoding); virtual void EmitCFILsda(const MCSymbol *Sym, unsigned Encoding); virtual void EmitCFIRememberState(); virtual void EmitCFIRestoreState(); virtual void EmitCFISameValue(int64_t Register); virtual void EmitCFIRestore(int64_t Register); virtual void EmitCFIRelOffset(int64_t Register, int64_t Offset); virtual void EmitCFIAdjustCfaOffset(int64_t Adjustment); virtual void EmitCFIEscape(StringRef Values); virtual void EmitCFIReturnColumn(int64_t Register); virtual void EmitCFIGnuArgsSize(int64_t Size); virtual void EmitCFISignalFrame(); virtual void EmitCFIUndefined(int64_t Register); virtual void EmitCFIRegister(int64_t Register1, int64_t Register2); virtual void EmitCFIWindowSave(); virtual void EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc = SMLoc()); virtual void EmitWinCFIEndProc(SMLoc Loc = SMLoc()); virtual void EmitWinCFIStartChained(SMLoc Loc = SMLoc()); virtual void EmitWinCFIEndChained(SMLoc Loc = SMLoc()); virtual void EmitWinCFIPushReg(unsigned Register, SMLoc Loc = SMLoc()); virtual void EmitWinCFISetFrame(unsigned Register, unsigned Offset, SMLoc Loc = SMLoc()); virtual void EmitWinCFIAllocStack(unsigned Size, SMLoc Loc = SMLoc()); virtual void EmitWinCFISaveReg(unsigned Register, unsigned Offset, SMLoc Loc = SMLoc()); virtual void EmitWinCFISaveXMM(unsigned Register, unsigned Offset, SMLoc Loc = SMLoc()); virtual void EmitWinCFIPushFrame(bool Code, SMLoc Loc = SMLoc()); virtual void EmitWinCFIEndProlog(SMLoc Loc = SMLoc()); virtual void EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except, SMLoc Loc = SMLoc()); virtual void EmitWinEHHandlerData(SMLoc Loc = SMLoc()); /// Get the .pdata section used for the given section. Typically the given /// section is either the main .text section or some other COMDAT .text /// section, but it may be any section containing code. MCSection *getAssociatedPDataSection(const MCSection *TextSec); /// Get the .xdata section used for the given section. MCSection *getAssociatedXDataSection(const MCSection *TextSec); virtual void EmitSyntaxDirective(); /// \brief Emit a .reloc directive. /// Returns true if the relocation could not be emitted because Name is not /// known. virtual bool EmitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr, SMLoc Loc) { return true; } /// \brief Emit the given \p Instruction into the current section. /// PrintSchedInfo == true then schedul comment should be added to output virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, bool PrintSchedInfo = false); /// \brief Set the bundle alignment mode from now on in the section. /// The argument is the power of 2 to which the alignment is set. The /// value 0 means turn the bundle alignment off. virtual void EmitBundleAlignMode(unsigned AlignPow2); /// \brief The following instructions are a bundle-locked group. /// /// \param AlignToEnd - If true, the bundle-locked group will be aligned to /// the end of a bundle. virtual void EmitBundleLock(bool AlignToEnd); /// \brief Ends a bundle-locked group. virtual void EmitBundleUnlock(); /// \brief If this file is backed by a assembly streamer, this dumps the /// specified string in the output .s file. This capability is indicated by /// the hasRawTextSupport() predicate. By default this aborts. void EmitRawText(const Twine &String); /// \brief Streamer specific finalization. virtual void FinishImpl(); /// \brief Finish emission of machine code. void Finish(); virtual bool mayHaveInstructions(MCSection &Sec) const { return true; } }; /// Create a dummy machine code streamer, which does nothing. This is useful for /// timing the assembler front end. MCStreamer *createNullStreamer(MCContext &Ctx); /// Create a machine code streamer which will print out assembly for the native /// target, suitable for compiling with a native assembler. /// /// \param InstPrint - If given, the instruction printer to use. If not given /// the MCInst representation will be printed. This method takes ownership of /// InstPrint. /// /// \param CE - If given, a code emitter to use to show the instruction /// encoding inline with the assembly. This method takes ownership of \p CE. /// /// \param TAB - If given, a target asm backend to use to show the fixup /// information in conjunction with encoding information. This method takes /// ownership of \p TAB. /// /// \param ShowInst - Whether to show the MCInst representation inline with /// the assembly. MCStreamer *createAsmStreamer(MCContext &Ctx, std::unique_ptr OS, bool isVerboseAsm, bool useDwarfDirectory, MCInstPrinter *InstPrint, MCCodeEmitter *CE, MCAsmBackend *TAB, bool ShowInst); } // end namespace llvm #endif // LLVM_MC_MCSTREAMER_H Index: head/contrib/llvm/lib/MC/ELFObjectWriter.cpp =================================================================== --- head/contrib/llvm/lib/MC/ELFObjectWriter.cpp (revision 331365) +++ head/contrib/llvm/lib/MC/ELFObjectWriter.cpp (revision 331366) @@ -1,1395 +1,1358 @@ //===- lib/MC/ELFObjectWriter.cpp - ELF File Writer -----------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements ELF object file writer information. // //===----------------------------------------------------------------------===// #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/ELF.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/MCELFObjectWriter.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCFragment.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolELF.h" #include "llvm/MC/MCValue.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/SwapByteOrder.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include #include #include #include using namespace llvm; #undef DEBUG_TYPE #define DEBUG_TYPE "reloc-info" namespace { using SectionIndexMapTy = DenseMap; class ELFObjectWriter; class SymbolTableWriter { ELFObjectWriter &EWriter; bool Is64Bit; // indexes we are going to write to .symtab_shndx. std::vector ShndxIndexes; // The numbel of symbols written so far. unsigned NumWritten; void createSymtabShndx(); template void write(T Value); public: SymbolTableWriter(ELFObjectWriter &EWriter, bool Is64Bit); void writeSymbol(uint32_t name, uint8_t info, uint64_t value, uint64_t size, uint8_t other, uint32_t shndx, bool Reserved); ArrayRef getShndxIndexes() const { return ShndxIndexes; } }; class ELFObjectWriter : public MCObjectWriter { static uint64_t SymbolValue(const MCSymbol &Sym, const MCAsmLayout &Layout); static bool isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol, bool Used, bool Renamed); /// Helper struct for containing some precomputed information on symbols. struct ELFSymbolData { const MCSymbolELF *Symbol; uint32_t SectionIndex; StringRef Name; // Support lexicographic sorting. bool operator<(const ELFSymbolData &RHS) const { unsigned LHSType = Symbol->getType(); unsigned RHSType = RHS.Symbol->getType(); if (LHSType == ELF::STT_SECTION && RHSType != ELF::STT_SECTION) return false; if (LHSType != ELF::STT_SECTION && RHSType == ELF::STT_SECTION) return true; if (LHSType == ELF::STT_SECTION && RHSType == ELF::STT_SECTION) return SectionIndex < RHS.SectionIndex; return Name < RHS.Name; } }; /// The target specific ELF writer instance. std::unique_ptr TargetObjectWriter; DenseMap Renames; DenseMap> Relocations; /// @} /// @name Symbol Table Data /// @{ - BumpPtrAllocator Alloc; - StringSaver VersionSymSaver{Alloc}; StringTableBuilder StrTabBuilder{StringTableBuilder::ELF}; /// @} // This holds the symbol table index of the last local symbol. unsigned LastLocalSymbolIndex; // This holds the .strtab section index. unsigned StringTableIndex; // This holds the .symtab section index. unsigned SymbolTableIndex; // Sections in the order they are to be output in the section table. std::vector SectionTable; unsigned addToSectionTable(const MCSectionELF *Sec); // TargetObjectWriter wrappers. bool is64Bit() const { return TargetObjectWriter->is64Bit(); } bool hasRelocationAddend() const { return TargetObjectWriter->hasRelocationAddend(); } unsigned getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { return TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel); } void align(unsigned Alignment); bool maybeWriteCompression(uint64_t Size, SmallVectorImpl &CompressedContents, bool ZLibStyle, unsigned Alignment); public: ELFObjectWriter(std::unique_ptr MOTW, raw_pwrite_stream &OS, bool IsLittleEndian) : MCObjectWriter(OS, IsLittleEndian), TargetObjectWriter(std::move(MOTW)) {} ~ELFObjectWriter() override = default; void reset() override { Renames.clear(); Relocations.clear(); StrTabBuilder.clear(); SectionTable.clear(); MCObjectWriter::reset(); } void WriteWord(uint64_t W) { if (is64Bit()) write64(W); else write32(W); } template void write(T Val) { if (IsLittleEndian) support::endian::Writer(getStream()).write(Val); else support::endian::Writer(getStream()).write(Val); } void writeHeader(const MCAssembler &Asm); void writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex, ELFSymbolData &MSD, const MCAsmLayout &Layout); // Start and end offset of each section using SectionOffsetsTy = std::map>; bool shouldRelocateWithSymbol(const MCAssembler &Asm, const MCSymbolRefExpr *RefA, const MCSymbol *Sym, uint64_t C, unsigned Type) const; void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) override; // Map from a signature symbol to the group section index using RevGroupMapTy = DenseMap; /// Compute the symbol table data /// /// \param Asm - The assembler. /// \param SectionIndexMap - Maps a section to its index. /// \param RevGroupMap - Maps a signature symbol to the group section. void computeSymbolTable(MCAssembler &Asm, const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const RevGroupMapTy &RevGroupMap, SectionOffsetsTy &SectionOffsets); MCSectionELF *createRelocationSection(MCContext &Ctx, const MCSectionELF &Sec); const MCSectionELF *createStringTable(MCContext &Ctx); void executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) override; void writeSectionHeader(const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const SectionOffsetsTy &SectionOffsets); void writeSectionData(const MCAssembler &Asm, MCSection &Sec, const MCAsmLayout &Layout); void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags, uint64_t Address, uint64_t Offset, uint64_t Size, uint32_t Link, uint32_t Info, uint64_t Alignment, uint64_t EntrySize); void writeRelocations(const MCAssembler &Asm, const MCSectionELF &Sec); using MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl; bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, const MCSymbol &SymA, const MCFragment &FB, bool InSet, bool IsPCRel) const override; void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; void writeSection(const SectionIndexMapTy &SectionIndexMap, uint32_t GroupSymbolIndex, uint64_t Offset, uint64_t Size, const MCSectionELF &Section); }; } // end anonymous namespace void ELFObjectWriter::align(unsigned Alignment) { uint64_t Padding = OffsetToAlignment(getStream().tell(), Alignment); WriteZeros(Padding); } unsigned ELFObjectWriter::addToSectionTable(const MCSectionELF *Sec) { SectionTable.push_back(Sec); StrTabBuilder.add(Sec->getSectionName()); return SectionTable.size(); } void SymbolTableWriter::createSymtabShndx() { if (!ShndxIndexes.empty()) return; ShndxIndexes.resize(NumWritten); } template void SymbolTableWriter::write(T Value) { EWriter.write(Value); } SymbolTableWriter::SymbolTableWriter(ELFObjectWriter &EWriter, bool Is64Bit) : EWriter(EWriter), Is64Bit(Is64Bit), NumWritten(0) {} void SymbolTableWriter::writeSymbol(uint32_t name, uint8_t info, uint64_t value, uint64_t size, uint8_t other, uint32_t shndx, bool Reserved) { bool LargeIndex = shndx >= ELF::SHN_LORESERVE && !Reserved; if (LargeIndex) createSymtabShndx(); if (!ShndxIndexes.empty()) { if (LargeIndex) ShndxIndexes.push_back(shndx); else ShndxIndexes.push_back(0); } uint16_t Index = LargeIndex ? uint16_t(ELF::SHN_XINDEX) : shndx; if (Is64Bit) { write(name); // st_name write(info); // st_info write(other); // st_other write(Index); // st_shndx write(value); // st_value write(size); // st_size } else { write(name); // st_name write(uint32_t(value)); // st_value write(uint32_t(size)); // st_size write(info); // st_info write(other); // st_other write(Index); // st_shndx } ++NumWritten; } // Emit the ELF header. void ELFObjectWriter::writeHeader(const MCAssembler &Asm) { // ELF Header // ---------- // // Note // ---- // emitWord method behaves differently for ELF32 and ELF64, writing // 4 bytes in the former and 8 in the latter. writeBytes(ELF::ElfMagic); // e_ident[EI_MAG0] to e_ident[EI_MAG3] write8(is64Bit() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS] // e_ident[EI_DATA] write8(isLittleEndian() ? ELF::ELFDATA2LSB : ELF::ELFDATA2MSB); write8(ELF::EV_CURRENT); // e_ident[EI_VERSION] // e_ident[EI_OSABI] write8(TargetObjectWriter->getOSABI()); write8(0); // e_ident[EI_ABIVERSION] WriteZeros(ELF::EI_NIDENT - ELF::EI_PAD); write16(ELF::ET_REL); // e_type write16(TargetObjectWriter->getEMachine()); // e_machine = target write32(ELF::EV_CURRENT); // e_version WriteWord(0); // e_entry, no entry point in .o file WriteWord(0); // e_phoff, no program header for .o WriteWord(0); // e_shoff = sec hdr table off in bytes // e_flags = whatever the target wants write32(Asm.getELFHeaderEFlags()); // e_ehsize = ELF header size write16(is64Bit() ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr)); write16(0); // e_phentsize = prog header entry size write16(0); // e_phnum = # prog header entries = 0 // e_shentsize = Section header entry size write16(is64Bit() ? sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr)); // e_shnum = # of section header ents write16(0); // e_shstrndx = Section # of '.shstrtab' assert(StringTableIndex < ELF::SHN_LORESERVE); write16(StringTableIndex); } uint64_t ELFObjectWriter::SymbolValue(const MCSymbol &Sym, const MCAsmLayout &Layout) { if (Sym.isCommon() && Sym.isExternal()) return Sym.getCommonAlignment(); uint64_t Res; if (!Layout.getSymbolOffset(Sym, Res)) return 0; if (Layout.getAssembler().isThumbFunc(&Sym)) Res |= 1; return Res; } void ELFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { // The presence of symbol versions causes undefined symbols and // versions declared with @@@ to be renamed. - for (const MCSymbol &A : Asm.symbols()) { - const auto &Alias = cast(A); - // Not an alias. - if (!Alias.isVariable()) - continue; - auto *Ref = dyn_cast(Alias.getVariableValue()); - if (!Ref) - continue; - const auto &Symbol = cast(Ref->getSymbol()); - - StringRef AliasName = Alias.getName(); + for (const std::pair &P : Asm.Symvers) { + StringRef AliasName = P.first; + const auto &Symbol = cast(*P.second); size_t Pos = AliasName.find('@'); - if (Pos == StringRef::npos) - continue; + assert(Pos != StringRef::npos); + StringRef Prefix = AliasName.substr(0, Pos); + StringRef Rest = AliasName.substr(Pos); + StringRef Tail = Rest; + if (Rest.startswith("@@@")) + Tail = Rest.substr(Symbol.isUndefined() ? 2 : 1); + + auto *Alias = + cast(Asm.getContext().getOrCreateSymbol(Prefix + Tail)); + Asm.registerSymbol(*Alias); + const MCExpr *Value = MCSymbolRefExpr::create(&Symbol, Asm.getContext()); + Alias->setVariableValue(Value); + // Aliases defined with .symvar copy the binding from the symbol they alias. // This is the first place we are able to copy this information. - Alias.setExternal(Symbol.isExternal()); - Alias.setBinding(Symbol.getBinding()); + Alias->setExternal(Symbol.isExternal()); + Alias->setBinding(Symbol.getBinding()); - StringRef Rest = AliasName.substr(Pos); if (!Symbol.isUndefined() && !Rest.startswith("@@@")) continue; // FIXME: produce a better error message. if (Symbol.isUndefined() && Rest.startswith("@@") && !Rest.startswith("@@@")) report_fatal_error("A @@ version cannot be undefined"); - Renames.insert(std::make_pair(&Symbol, &Alias)); + Renames.insert(std::make_pair(&Symbol, Alias)); } } static uint8_t mergeTypeForSet(uint8_t origType, uint8_t newType) { uint8_t Type = newType; // Propagation rules: // IFUNC > FUNC > OBJECT > NOTYPE // TLS_OBJECT > OBJECT > NOTYPE // // dont let the new type degrade the old type switch (origType) { default: break; case ELF::STT_GNU_IFUNC: if (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT || Type == ELF::STT_NOTYPE || Type == ELF::STT_TLS) Type = ELF::STT_GNU_IFUNC; break; case ELF::STT_FUNC: if (Type == ELF::STT_OBJECT || Type == ELF::STT_NOTYPE || Type == ELF::STT_TLS) Type = ELF::STT_FUNC; break; case ELF::STT_OBJECT: if (Type == ELF::STT_NOTYPE) Type = ELF::STT_OBJECT; break; case ELF::STT_TLS: if (Type == ELF::STT_OBJECT || Type == ELF::STT_NOTYPE || Type == ELF::STT_GNU_IFUNC || Type == ELF::STT_FUNC) Type = ELF::STT_TLS; break; } return Type; } void ELFObjectWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex, ELFSymbolData &MSD, const MCAsmLayout &Layout) { const auto &Symbol = cast(*MSD.Symbol); const MCSymbolELF *Base = cast_or_null(Layout.getBaseSymbol(Symbol)); // This has to be in sync with when computeSymbolTable uses SHN_ABS or // SHN_COMMON. bool IsReserved = !Base || Symbol.isCommon(); // Binding and Type share the same byte as upper and lower nibbles uint8_t Binding = Symbol.getBinding(); uint8_t Type = Symbol.getType(); if (Base) { Type = mergeTypeForSet(Type, Base->getType()); } uint8_t Info = (Binding << 4) | Type; // Other and Visibility share the same byte with Visibility using the lower // 2 bits uint8_t Visibility = Symbol.getVisibility(); uint8_t Other = Symbol.getOther() | Visibility; uint64_t Value = SymbolValue(*MSD.Symbol, Layout); uint64_t Size = 0; const MCExpr *ESize = MSD.Symbol->getSize(); if (!ESize && Base) ESize = Base->getSize(); if (ESize) { int64_t Res; if (!ESize->evaluateKnownAbsolute(Res, Layout)) report_fatal_error("Size expression must be absolute."); Size = Res; } // Write out the symbol table entry Writer.writeSymbol(StringIndex, Info, Value, Size, Other, MSD.SectionIndex, IsReserved); } // It is always valid to create a relocation with a symbol. It is preferable // to use a relocation with a section if that is possible. Using the section // allows us to omit some local symbols from the symbol table. bool ELFObjectWriter::shouldRelocateWithSymbol(const MCAssembler &Asm, const MCSymbolRefExpr *RefA, const MCSymbol *S, uint64_t C, unsigned Type) const { const auto *Sym = cast_or_null(S); // A PCRel relocation to an absolute value has no symbol (or section). We // represent that with a relocation to a null section. if (!RefA) return false; MCSymbolRefExpr::VariantKind Kind = RefA->getKind(); switch (Kind) { default: break; // The .odp creation emits a relocation against the symbol ".TOC." which // create a R_PPC64_TOC relocation. However the relocation symbol name // in final object creation should be NULL, since the symbol does not // really exist, it is just the reference to TOC base for the current // object file. Since the symbol is undefined, returning false results // in a relocation with a null section which is the desired result. case MCSymbolRefExpr::VK_PPC_TOCBASE: return false; // These VariantKind cause the relocation to refer to something other than // the symbol itself, like a linker generated table. Since the address of // symbol is not relevant, we cannot replace the symbol with the // section and patch the difference in the addend. case MCSymbolRefExpr::VK_GOT: case MCSymbolRefExpr::VK_PLT: case MCSymbolRefExpr::VK_GOTPCREL: case MCSymbolRefExpr::VK_PPC_GOT_LO: case MCSymbolRefExpr::VK_PPC_GOT_HI: case MCSymbolRefExpr::VK_PPC_GOT_HA: return true; } // An undefined symbol is not in any section, so the relocation has to point // to the symbol itself. assert(Sym && "Expected a symbol"); if (Sym->isUndefined()) return true; unsigned Binding = Sym->getBinding(); switch(Binding) { default: llvm_unreachable("Invalid Binding"); case ELF::STB_LOCAL: break; case ELF::STB_WEAK: // If the symbol is weak, it might be overridden by a symbol in another // file. The relocation has to point to the symbol so that the linker // can update it. return true; case ELF::STB_GLOBAL: // Global ELF symbols can be preempted by the dynamic linker. The relocation // has to point to the symbol for a reason analogous to the STB_WEAK case. return true; } // If a relocation points to a mergeable section, we have to be careful. // If the offset is zero, a relocation with the section will encode the // same information. With a non-zero offset, the situation is different. // For example, a relocation can point 42 bytes past the end of a string. // If we change such a relocation to use the section, the linker would think // that it pointed to another string and subtracting 42 at runtime will // produce the wrong value. if (Sym->isInSection()) { auto &Sec = cast(Sym->getSection()); unsigned Flags = Sec.getFlags(); if (Flags & ELF::SHF_MERGE) { if (C != 0) return true; // It looks like gold has a bug (http://sourceware.org/PR16794) and can // only handle section relocations to mergeable sections if using RELA. if (!hasRelocationAddend()) return true; } // Most TLS relocations use a got, so they need the symbol. Even those that // are just an offset (@tpoff), require a symbol in gold versions before // 5efeedf61e4fe720fd3e9a08e6c91c10abb66d42 (2014-09-26) which fixed // http://sourceware.org/PR16773. if (Flags & ELF::SHF_TLS) return true; } // If the symbol is a thumb function the final relocation must set the lowest // bit. With a symbol that is done by just having the symbol have that bit // set, so we would lose the bit if we relocated with the section. // FIXME: We could use the section but add the bit to the relocation value. if (Asm.isThumbFunc(Sym)) return true; if (TargetObjectWriter->needsRelocateWithSymbol(*Sym, Type)) return true; return false; } // True if the assembler knows nothing about the final value of the symbol. // This doesn't cover the comdat issues, since in those cases the assembler // can at least know that all symbols in the section will move together. static bool isWeak(const MCSymbolELF &Sym) { if (Sym.getType() == ELF::STT_GNU_IFUNC) return true; switch (Sym.getBinding()) { default: llvm_unreachable("Unknown binding"); case ELF::STB_LOCAL: return false; case ELF::STB_GLOBAL: return false; case ELF::STB_WEAK: case ELF::STB_GNU_UNIQUE: return true; } } void ELFObjectWriter::recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { MCAsmBackend &Backend = Asm.getBackend(); bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; const MCSectionELF &FixupSection = cast(*Fragment->getParent()); uint64_t C = Target.getConstant(); uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); MCContext &Ctx = Asm.getContext(); if (const MCSymbolRefExpr *RefB = Target.getSymB()) { // Let A, B and C being the components of Target and R be the location of // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). // If it is pcrel, we want to compute (A - B + C - R). // In general, ELF has no relocations for -B. It can only represent (A + C) // or (A + C - R). If B = R + K and the relocation is not pcrel, we can // replace B to implement it: (A - R - K + C) if (IsPCRel) { Ctx.reportError( Fixup.getLoc(), "No relocation available to represent this relative expression"); return; } const auto &SymB = cast(RefB->getSymbol()); if (SymB.isUndefined()) { Ctx.reportError(Fixup.getLoc(), Twine("symbol '") + SymB.getName() + "' can not be undefined in a subtraction expression"); return; } assert(!SymB.isAbsolute() && "Should have been folded"); const MCSection &SecB = SymB.getSection(); if (&SecB != &FixupSection) { Ctx.reportError(Fixup.getLoc(), "Cannot represent a difference across sections"); return; } uint64_t SymBOffset = Layout.getSymbolOffset(SymB); uint64_t K = SymBOffset - FixupOffset; IsPCRel = true; C -= K; } // We either rejected the fixup or folded B into C at this point. const MCSymbolRefExpr *RefA = Target.getSymA(); const auto *SymA = RefA ? cast(&RefA->getSymbol()) : nullptr; bool ViaWeakRef = false; if (SymA && SymA->isVariable()) { const MCExpr *Expr = SymA->getVariableValue(); if (const auto *Inner = dyn_cast(Expr)) { if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) { SymA = cast(&Inner->getSymbol()); ViaWeakRef = true; } } } unsigned Type = getRelocType(Ctx, Target, Fixup, IsPCRel); uint64_t OriginalC = C; bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type); if (!RelocateWithSymbol && SymA && !SymA->isUndefined()) C += Layout.getSymbolOffset(*SymA); uint64_t Addend = 0; if (hasRelocationAddend()) { Addend = C; C = 0; } FixedValue = C; if (!RelocateWithSymbol) { const MCSection *SecA = (SymA && !SymA->isUndefined()) ? &SymA->getSection() : nullptr; auto *ELFSec = cast_or_null(SecA); const auto *SectionSymbol = ELFSec ? cast(ELFSec->getBeginSymbol()) : nullptr; if (SectionSymbol) SectionSymbol->setUsedInReloc(); ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend, SymA, OriginalC); Relocations[&FixupSection].push_back(Rec); return; } const auto *RenamedSymA = SymA; if (SymA) { if (const MCSymbolELF *R = Renames.lookup(SymA)) RenamedSymA = R; if (ViaWeakRef) RenamedSymA->setIsWeakrefUsedInReloc(); else RenamedSymA->setUsedInReloc(); } ELFRelocationEntry Rec(FixupOffset, RenamedSymA, Type, Addend, SymA, OriginalC); Relocations[&FixupSection].push_back(Rec); } bool ELFObjectWriter::isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol, bool Used, bool Renamed) { if (Symbol.isVariable()) { const MCExpr *Expr = Symbol.getVariableValue(); if (const MCSymbolRefExpr *Ref = dyn_cast(Expr)) { if (Ref->getKind() == MCSymbolRefExpr::VK_WEAKREF) return false; } } if (Used) return true; if (Renamed) return false; if (Symbol.isVariable() && Symbol.isUndefined()) { // FIXME: this is here just to diagnose the case of a var = commmon_sym. Layout.getBaseSymbol(Symbol); return false; } if (Symbol.isUndefined() && !Symbol.isBindingSet()) return false; if (Symbol.isTemporary()) return false; if (Symbol.getType() == ELF::STT_SECTION) return false; return true; } void ELFObjectWriter::computeSymbolTable( MCAssembler &Asm, const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const RevGroupMapTy &RevGroupMap, SectionOffsetsTy &SectionOffsets) { MCContext &Ctx = Asm.getContext(); SymbolTableWriter Writer(*this, is64Bit()); // Symbol table unsigned EntrySize = is64Bit() ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; MCSectionELF *SymtabSection = Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, EntrySize, ""); SymtabSection->setAlignment(is64Bit() ? 8 : 4); SymbolTableIndex = addToSectionTable(SymtabSection); align(SymtabSection->getAlignment()); uint64_t SecStart = getStream().tell(); // The first entry is the undefined symbol entry. Writer.writeSymbol(0, 0, 0, 0, 0, 0, false); std::vector LocalSymbolData; std::vector ExternalSymbolData; // Add the data for the symbols. bool HasLargeSectionIndex = false; for (const MCSymbol &S : Asm.symbols()) { const auto &Symbol = cast(S); bool Used = Symbol.isUsedInReloc(); bool WeakrefUsed = Symbol.isWeakrefUsedInReloc(); bool isSignature = Symbol.isSignature(); if (!isInSymtab(Layout, Symbol, Used || WeakrefUsed || isSignature, Renames.count(&Symbol))) continue; if (Symbol.isTemporary() && Symbol.isUndefined()) { Ctx.reportError(SMLoc(), "Undefined temporary symbol"); continue; } ELFSymbolData MSD; MSD.Symbol = cast(&Symbol); bool Local = Symbol.getBinding() == ELF::STB_LOCAL; assert(Local || !Symbol.isTemporary()); if (Symbol.isAbsolute()) { MSD.SectionIndex = ELF::SHN_ABS; } else if (Symbol.isCommon()) { assert(!Local); MSD.SectionIndex = ELF::SHN_COMMON; } else if (Symbol.isUndefined()) { if (isSignature && !Used) { MSD.SectionIndex = RevGroupMap.lookup(&Symbol); if (MSD.SectionIndex >= ELF::SHN_LORESERVE) HasLargeSectionIndex = true; } else { MSD.SectionIndex = ELF::SHN_UNDEF; } } else { const MCSectionELF &Section = static_cast(Symbol.getSection()); MSD.SectionIndex = SectionIndexMap.lookup(&Section); assert(MSD.SectionIndex && "Invalid section index!"); if (MSD.SectionIndex >= ELF::SHN_LORESERVE) HasLargeSectionIndex = true; } - // The @@@ in symbol version is replaced with @ in undefined symbols and @@ - // in defined ones. - // - // FIXME: All name handling should be done before we get to the writer, - // including dealing with GNU-style version suffixes. Fixing this isn't - // trivial. - // - // We thus have to be careful to not perform the symbol version replacement - // blindly: - // - // The ELF format is used on Windows by the MCJIT engine. Thus, on - // Windows, the ELFObjectWriter can encounter symbols mangled using the MS - // Visual Studio C++ name mangling scheme. Symbols mangled using the MSVC - // C++ name mangling can legally have "@@@" as a sub-string. In that case, - // the EFLObjectWriter should not interpret the "@@@" sub-string as - // specifying GNU-style symbol versioning. The ELFObjectWriter therefore - // checks for the MSVC C++ name mangling prefix which is either "?", "@?", - // "__imp_?" or "__imp_@?". - // - // It would have been interesting to perform the MS mangling prefix check - // only when the target triple is of the form *-pc-windows-elf. But, it - // seems that this information is not easily accessible from the - // ELFObjectWriter. StringRef Name = Symbol.getName(); - SmallString<32> Buf; - if (!Name.startswith("?") && !Name.startswith("@?") && - !Name.startswith("__imp_?") && !Name.startswith("__imp_@?")) { - // This symbol isn't following the MSVC C++ name mangling convention. We - // can thus safely interpret the @@@ in symbol names as specifying symbol - // versioning. - size_t Pos = Name.find("@@@"); - if (Pos != StringRef::npos) { - Buf += Name.substr(0, Pos); - unsigned Skip = MSD.SectionIndex == ELF::SHN_UNDEF ? 2 : 1; - Buf += Name.substr(Pos + Skip); - Name = VersionSymSaver.save(Buf.c_str()); - } - } // Sections have their own string table if (Symbol.getType() != ELF::STT_SECTION) { MSD.Name = Name; StrTabBuilder.add(Name); } if (Local) LocalSymbolData.push_back(MSD); else ExternalSymbolData.push_back(MSD); } // This holds the .symtab_shndx section index. unsigned SymtabShndxSectionIndex = 0; if (HasLargeSectionIndex) { MCSectionELF *SymtabShndxSection = Ctx.getELFSection(".symtab_shndxr", ELF::SHT_SYMTAB_SHNDX, 0, 4, ""); SymtabShndxSectionIndex = addToSectionTable(SymtabShndxSection); SymtabShndxSection->setAlignment(4); } ArrayRef FileNames = Asm.getFileNames(); for (const std::string &Name : FileNames) StrTabBuilder.add(Name); StrTabBuilder.finalize(); // File symbols are emitted first and handled separately from normal symbols, // i.e. a non-STT_FILE symbol with the same name may appear. for (const std::string &Name : FileNames) Writer.writeSymbol(StrTabBuilder.getOffset(Name), ELF::STT_FILE | ELF::STB_LOCAL, 0, 0, ELF::STV_DEFAULT, ELF::SHN_ABS, true); // Symbols are required to be in lexicographic order. array_pod_sort(LocalSymbolData.begin(), LocalSymbolData.end()); array_pod_sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); // Set the symbol indices. Local symbols must come before all other // symbols with non-local bindings. unsigned Index = FileNames.size() + 1; for (ELFSymbolData &MSD : LocalSymbolData) { unsigned StringIndex = MSD.Symbol->getType() == ELF::STT_SECTION ? 0 : StrTabBuilder.getOffset(MSD.Name); MSD.Symbol->setIndex(Index++); writeSymbol(Writer, StringIndex, MSD, Layout); } // Write the symbol table entries. LastLocalSymbolIndex = Index; for (ELFSymbolData &MSD : ExternalSymbolData) { unsigned StringIndex = StrTabBuilder.getOffset(MSD.Name); MSD.Symbol->setIndex(Index++); writeSymbol(Writer, StringIndex, MSD, Layout); assert(MSD.Symbol->getBinding() != ELF::STB_LOCAL); } uint64_t SecEnd = getStream().tell(); SectionOffsets[SymtabSection] = std::make_pair(SecStart, SecEnd); ArrayRef ShndxIndexes = Writer.getShndxIndexes(); if (ShndxIndexes.empty()) { assert(SymtabShndxSectionIndex == 0); return; } assert(SymtabShndxSectionIndex != 0); SecStart = getStream().tell(); const MCSectionELF *SymtabShndxSection = SectionTable[SymtabShndxSectionIndex - 1]; for (uint32_t Index : ShndxIndexes) write(Index); SecEnd = getStream().tell(); SectionOffsets[SymtabShndxSection] = std::make_pair(SecStart, SecEnd); } MCSectionELF * ELFObjectWriter::createRelocationSection(MCContext &Ctx, const MCSectionELF &Sec) { if (Relocations[&Sec].empty()) return nullptr; const StringRef SectionName = Sec.getSectionName(); std::string RelaSectionName = hasRelocationAddend() ? ".rela" : ".rel"; RelaSectionName += SectionName; unsigned EntrySize; if (hasRelocationAddend()) EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rela) : sizeof(ELF::Elf32_Rela); else EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rel) : sizeof(ELF::Elf32_Rel); unsigned Flags = 0; if (Sec.getFlags() & ELF::SHF_GROUP) Flags = ELF::SHF_GROUP; MCSectionELF *RelaSection = Ctx.createELFRelSection( RelaSectionName, hasRelocationAddend() ? ELF::SHT_RELA : ELF::SHT_REL, Flags, EntrySize, Sec.getGroup(), &Sec); RelaSection->setAlignment(is64Bit() ? 8 : 4); return RelaSection; } // Include the debug info compression header. bool ELFObjectWriter::maybeWriteCompression( uint64_t Size, SmallVectorImpl &CompressedContents, bool ZLibStyle, unsigned Alignment) { if (ZLibStyle) { uint64_t HdrSize = is64Bit() ? sizeof(ELF::Elf32_Chdr) : sizeof(ELF::Elf64_Chdr); if (Size <= HdrSize + CompressedContents.size()) return false; // Platform specific header is followed by compressed data. if (is64Bit()) { // Write Elf64_Chdr header. write(static_cast(ELF::ELFCOMPRESS_ZLIB)); write(static_cast(0)); // ch_reserved field. write(static_cast(Size)); write(static_cast(Alignment)); } else { // Write Elf32_Chdr header otherwise. write(static_cast(ELF::ELFCOMPRESS_ZLIB)); write(static_cast(Size)); write(static_cast(Alignment)); } return true; } // "ZLIB" followed by 8 bytes representing the uncompressed size of the section, // useful for consumers to preallocate a buffer to decompress into. const StringRef Magic = "ZLIB"; if (Size <= Magic.size() + sizeof(Size) + CompressedContents.size()) return false; write(ArrayRef(Magic.begin(), Magic.size())); writeBE64(Size); return true; } void ELFObjectWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec, const MCAsmLayout &Layout) { MCSectionELF &Section = static_cast(Sec); StringRef SectionName = Section.getSectionName(); auto &MC = Asm.getContext(); const auto &MAI = MC.getAsmInfo(); // Compressing debug_frame requires handling alignment fragments which is // more work (possibly generalizing MCAssembler.cpp:writeFragment to allow // for writing to arbitrary buffers) for little benefit. bool CompressionEnabled = MAI->compressDebugSections() != DebugCompressionType::None; if (!CompressionEnabled || !SectionName.startswith(".debug_") || SectionName == ".debug_frame") { Asm.writeSectionData(&Section, Layout); return; } assert((MAI->compressDebugSections() == DebugCompressionType::Z || MAI->compressDebugSections() == DebugCompressionType::GNU) && "expected zlib or zlib-gnu style compression"); SmallVector UncompressedData; raw_svector_ostream VecOS(UncompressedData); raw_pwrite_stream &OldStream = getStream(); setStream(VecOS); Asm.writeSectionData(&Section, Layout); setStream(OldStream); SmallVector CompressedContents; if (Error E = zlib::compress( StringRef(UncompressedData.data(), UncompressedData.size()), CompressedContents)) { consumeError(std::move(E)); getStream() << UncompressedData; return; } bool ZlibStyle = MAI->compressDebugSections() == DebugCompressionType::Z; if (!maybeWriteCompression(UncompressedData.size(), CompressedContents, ZlibStyle, Sec.getAlignment())) { getStream() << UncompressedData; return; } if (ZlibStyle) // Set the compressed flag. That is zlib style. Section.setFlags(Section.getFlags() | ELF::SHF_COMPRESSED); else // Add "z" prefix to section name. This is zlib-gnu style. MC.renameELFSection(&Section, (".z" + SectionName.drop_front(1)).str()); getStream() << CompressedContents; } void ELFObjectWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags, uint64_t Address, uint64_t Offset, uint64_t Size, uint32_t Link, uint32_t Info, uint64_t Alignment, uint64_t EntrySize) { write32(Name); // sh_name: index into string table write32(Type); // sh_type WriteWord(Flags); // sh_flags WriteWord(Address); // sh_addr WriteWord(Offset); // sh_offset WriteWord(Size); // sh_size write32(Link); // sh_link write32(Info); // sh_info WriteWord(Alignment); // sh_addralign WriteWord(EntrySize); // sh_entsize } void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, const MCSectionELF &Sec) { std::vector &Relocs = Relocations[&Sec]; // We record relocations by pushing to the end of a vector. Reverse the vector // to get the relocations in the order they were created. // In most cases that is not important, but it can be for special sections // (.eh_frame) or specific relocations (TLS optimizations on SystemZ). std::reverse(Relocs.begin(), Relocs.end()); // Sort the relocation entries. MIPS needs this. TargetObjectWriter->sortRelocs(Asm, Relocs); for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { const ELFRelocationEntry &Entry = Relocs[e - i - 1]; unsigned Index = Entry.Symbol ? Entry.Symbol->getIndex() : 0; if (is64Bit()) { write(Entry.Offset); if (TargetObjectWriter->getEMachine() == ELF::EM_MIPS) { write(uint32_t(Index)); write(TargetObjectWriter->getRSsym(Entry.Type)); write(TargetObjectWriter->getRType3(Entry.Type)); write(TargetObjectWriter->getRType2(Entry.Type)); write(TargetObjectWriter->getRType(Entry.Type)); } else { struct ELF::Elf64_Rela ERE64; ERE64.setSymbolAndType(Index, Entry.Type); write(ERE64.r_info); } if (hasRelocationAddend()) write(Entry.Addend); } else { write(uint32_t(Entry.Offset)); struct ELF::Elf32_Rela ERE32; ERE32.setSymbolAndType(Index, Entry.Type); write(ERE32.r_info); 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)); } } } } } const MCSectionELF *ELFObjectWriter::createStringTable(MCContext &Ctx) { const MCSectionELF *StrtabSection = SectionTable[StringTableIndex - 1]; StrTabBuilder.write(getStream()); return StrtabSection; } void ELFObjectWriter::writeSection(const SectionIndexMapTy &SectionIndexMap, uint32_t GroupSymbolIndex, uint64_t Offset, uint64_t Size, const MCSectionELF &Section) { uint64_t sh_link = 0; uint64_t sh_info = 0; switch(Section.getType()) { default: // Nothing to do. break; case ELF::SHT_DYNAMIC: llvm_unreachable("SHT_DYNAMIC in a relocatable object"); case ELF::SHT_REL: case ELF::SHT_RELA: { sh_link = SymbolTableIndex; assert(sh_link && ".symtab not found"); const MCSection *InfoSection = Section.getAssociatedSection(); sh_info = SectionIndexMap.lookup(cast(InfoSection)); break; } case ELF::SHT_SYMTAB: case ELF::SHT_DYNSYM: sh_link = StringTableIndex; sh_info = LastLocalSymbolIndex; break; case ELF::SHT_SYMTAB_SHNDX: sh_link = SymbolTableIndex; break; case ELF::SHT_GROUP: sh_link = SymbolTableIndex; sh_info = GroupSymbolIndex; break; } if (Section.getFlags() & ELF::SHF_LINK_ORDER) { const MCSymbol *Sym = Section.getAssociatedSymbol(); const MCSectionELF *Sec = cast(&Sym->getSection()); sh_link = SectionIndexMap.lookup(Sec); } WriteSecHdrEntry(StrTabBuilder.getOffset(Section.getSectionName()), Section.getType(), Section.getFlags(), 0, Offset, Size, sh_link, sh_info, Section.getAlignment(), Section.getEntrySize()); } void ELFObjectWriter::writeSectionHeader( const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const SectionOffsetsTy &SectionOffsets) { const unsigned NumSections = SectionTable.size(); // Null section first. uint64_t FirstSectionSize = (NumSections + 1) >= ELF::SHN_LORESERVE ? NumSections + 1 : 0; WriteSecHdrEntry(0, 0, 0, 0, 0, FirstSectionSize, 0, 0, 0, 0); for (const MCSectionELF *Section : SectionTable) { uint32_t GroupSymbolIndex; unsigned Type = Section->getType(); if (Type != ELF::SHT_GROUP) GroupSymbolIndex = 0; else GroupSymbolIndex = Section->getGroup()->getIndex(); const std::pair &Offsets = SectionOffsets.find(Section)->second; uint64_t Size; if (Type == ELF::SHT_NOBITS) Size = Layout.getSectionAddressSize(Section); else Size = Offsets.second - Offsets.first; writeSection(SectionIndexMap, GroupSymbolIndex, Offsets.first, Size, *Section); } } void ELFObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { MCContext &Ctx = Asm.getContext(); MCSectionELF *StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0); StringTableIndex = addToSectionTable(StrtabSection); RevGroupMapTy RevGroupMap; SectionIndexMapTy SectionIndexMap; std::map> GroupMembers; // Write out the ELF header ... writeHeader(Asm); // ... then the sections ... SectionOffsetsTy SectionOffsets; std::vector Groups; std::vector Relocations; for (MCSection &Sec : Asm) { MCSectionELF &Section = static_cast(Sec); align(Section.getAlignment()); // Remember the offset into the file for this section. uint64_t SecStart = getStream().tell(); const MCSymbolELF *SignatureSymbol = Section.getGroup(); writeSectionData(Asm, Section, Layout); uint64_t SecEnd = getStream().tell(); SectionOffsets[&Section] = std::make_pair(SecStart, SecEnd); MCSectionELF *RelSection = createRelocationSection(Ctx, Section); if (SignatureSymbol) { Asm.registerSymbol(*SignatureSymbol); unsigned &GroupIdx = RevGroupMap[SignatureSymbol]; if (!GroupIdx) { MCSectionELF *Group = Ctx.createELFGroupSection(SignatureSymbol); GroupIdx = addToSectionTable(Group); Group->setAlignment(4); Groups.push_back(Group); } std::vector &Members = GroupMembers[SignatureSymbol]; Members.push_back(&Section); if (RelSection) Members.push_back(RelSection); } SectionIndexMap[&Section] = addToSectionTable(&Section); if (RelSection) { SectionIndexMap[RelSection] = addToSectionTable(RelSection); Relocations.push_back(RelSection); } } for (MCSectionELF *Group : Groups) { align(Group->getAlignment()); // Remember the offset into the file for this section. uint64_t SecStart = getStream().tell(); const MCSymbol *SignatureSymbol = Group->getGroup(); assert(SignatureSymbol); write(uint32_t(ELF::GRP_COMDAT)); for (const MCSectionELF *Member : GroupMembers[SignatureSymbol]) { uint32_t SecIndex = SectionIndexMap.lookup(Member); write(SecIndex); } uint64_t SecEnd = getStream().tell(); SectionOffsets[Group] = std::make_pair(SecStart, SecEnd); } // Compute symbol table information. computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap, SectionOffsets); for (MCSectionELF *RelSection : Relocations) { align(RelSection->getAlignment()); // Remember the offset into the file for this section. uint64_t SecStart = getStream().tell(); writeRelocations(Asm, cast(*RelSection->getAssociatedSection())); uint64_t SecEnd = getStream().tell(); SectionOffsets[RelSection] = std::make_pair(SecStart, SecEnd); } { uint64_t SecStart = getStream().tell(); const MCSectionELF *Sec = createStringTable(Ctx); uint64_t SecEnd = getStream().tell(); SectionOffsets[Sec] = std::make_pair(SecStart, SecEnd); } uint64_t NaturalAlignment = is64Bit() ? 8 : 4; align(NaturalAlignment); const uint64_t SectionHeaderOffset = getStream().tell(); // ... then the section header table ... writeSectionHeader(Layout, SectionIndexMap, SectionOffsets); uint16_t NumSections = (SectionTable.size() + 1 >= ELF::SHN_LORESERVE) ? (uint16_t)ELF::SHN_UNDEF : SectionTable.size() + 1; if (sys::IsLittleEndianHost != IsLittleEndian) sys::swapByteOrder(NumSections); unsigned NumSectionsOffset; if (is64Bit()) { uint64_t Val = SectionHeaderOffset; if (sys::IsLittleEndianHost != IsLittleEndian) sys::swapByteOrder(Val); getStream().pwrite(reinterpret_cast(&Val), sizeof(Val), offsetof(ELF::Elf64_Ehdr, e_shoff)); NumSectionsOffset = offsetof(ELF::Elf64_Ehdr, e_shnum); } else { uint32_t Val = SectionHeaderOffset; if (sys::IsLittleEndianHost != IsLittleEndian) sys::swapByteOrder(Val); getStream().pwrite(reinterpret_cast(&Val), sizeof(Val), offsetof(ELF::Elf32_Ehdr, e_shoff)); NumSectionsOffset = offsetof(ELF::Elf32_Ehdr, e_shnum); } getStream().pwrite(reinterpret_cast(&NumSections), sizeof(NumSections), NumSectionsOffset); } bool ELFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl( const MCAssembler &Asm, const MCSymbol &SA, const MCFragment &FB, bool InSet, bool IsPCRel) const { const auto &SymA = cast(SA); if (IsPCRel) { assert(!InSet); if (isWeak(SymA)) return false; } return MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(Asm, SymA, FB, InSet, IsPCRel); } std::unique_ptr llvm::createELFObjectWriter(std::unique_ptr MOTW, raw_pwrite_stream &OS, bool IsLittleEndian) { return llvm::make_unique(std::move(MOTW), OS, IsLittleEndian); } Index: head/contrib/llvm/lib/MC/MCAsmStreamer.cpp =================================================================== --- head/contrib/llvm/lib/MC/MCAsmStreamer.cpp (revision 331365) +++ head/contrib/llvm/lib/MC/MCAsmStreamer.cpp (revision 331366) @@ -1,1788 +1,1799 @@ //===- lib/MC/MCAsmStreamer.cpp - Text Assembly Output ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.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 using namespace llvm; namespace { class MCAsmStreamer final : public MCStreamer { std::unique_ptr OSOwner; formatted_raw_ostream &OS; const MCAsmInfo *MAI; std::unique_ptr InstPrinter; std::unique_ptr Emitter; std::unique_ptr AsmBackend; SmallString<128> ExplicitCommentToEmit; SmallString<128> CommentToEmit; raw_svector_ostream CommentStream; unsigned IsVerboseAsm : 1; unsigned ShowInst : 1; unsigned UseDwarfDirectory : 1; void EmitRegisterName(int64_t Register); void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override; void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override; public: MCAsmStreamer(MCContext &Context, std::unique_ptr os, bool isVerboseAsm, bool useDwarfDirectory, MCInstPrinter *printer, MCCodeEmitter *emitter, MCAsmBackend *asmbackend, bool showInst) : MCStreamer(Context), OSOwner(std::move(os)), OS(*OSOwner), MAI(Context.getAsmInfo()), InstPrinter(printer), Emitter(emitter), AsmBackend(asmbackend), CommentStream(CommentToEmit), IsVerboseAsm(isVerboseAsm), ShowInst(showInst), UseDwarfDirectory(useDwarfDirectory) { assert(InstPrinter); if (IsVerboseAsm) InstPrinter->setCommentStream(CommentStream); } inline void EmitEOL() { // Dump Explicit Comments here. emitExplicitComments(); // If we don't have any comments, just emit a \n. if (!IsVerboseAsm) { OS << '\n'; return; } EmitCommentsAndEOL(); } void EmitSyntaxDirective() override; void EmitCommentsAndEOL(); /// isVerboseAsm - Return true if this streamer supports verbose assembly at /// all. bool isVerboseAsm() const override { return IsVerboseAsm; } /// hasRawTextSupport - We support EmitRawText. bool hasRawTextSupport() const override { return true; } /// AddComment - Add a comment that can be emitted to the generated .s /// file if applicable as a QoI issue to make the output of the compiler /// more readable. This only affects the MCAsmStreamer, and only when /// verbose assembly output is enabled. void AddComment(const Twine &T, bool EOL = true) override; /// AddEncodingComment - Add a comment showing the encoding of an instruction. /// If PrintSchedInfo - is true then the comment sched:[x:y] should // be added to output if it's being supported by target void AddEncodingComment(const MCInst &Inst, const MCSubtargetInfo &, bool PrintSchedInfo); /// GetCommentOS - Return a raw_ostream that comments can be written to. /// Unlike AddComment, you are required to terminate comments with \n if you /// use this method. raw_ostream &GetCommentOS() override { if (!IsVerboseAsm) return nulls(); // Discard comments unless in verbose asm mode. return CommentStream; } void emitRawComment(const Twine &T, bool TabPrefix = true) override; void addExplicitComment(const Twine &T) override; void emitExplicitComments() override; /// AddBlankLine - Emit a blank line to a .s file to pretty it up. void AddBlankLine() override { EmitEOL(); } /// @name MCStreamer Interface /// @{ void ChangeSection(MCSection *Section, const MCExpr *Subsection) override; + void emitELFSymverDirective(StringRef AliasName, + const MCSymbol *Aliasee) override; + void EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) override; void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override; void EmitAssemblerFlag(MCAssemblerFlag Flag) override; void EmitLinkerOptions(ArrayRef Options) override; void EmitDataRegion(MCDataRegionType Kind) override; void EmitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor, unsigned Update) override; void EmitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor, unsigned Update) override; void EmitThumbFunc(MCSymbol *Func) override; void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override; bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override; void BeginCOFFSymbolDef(const MCSymbol *Symbol) override; void EmitCOFFSymbolStorageClass(int StorageClass) override; void EmitCOFFSymbolType(int Type) override; void EndCOFFSymbolDef() override; void EmitCOFFSafeSEH(MCSymbol const *Symbol) override; void EmitCOFFSectionIndex(MCSymbol const *Symbol) override; void EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override; void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; /// EmitLocalCommonSymbol - Emit a local common (.lcomm) symbol. /// /// @param Symbol - The common symbol to emit. /// @param Size - The size of the common symbol. /// @param ByteAlignment - The alignment of the common symbol in bytes. void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, uint64_t Size = 0, unsigned ByteAlignment = 0) override; void EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment = 0) override; void EmitBinaryData(StringRef Data) override; void EmitBytes(StringRef Data) override; void EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc = SMLoc()) override; void EmitIntValue(uint64_t Value, unsigned Size) override; void EmitULEB128Value(const MCExpr *Value) override; void EmitSLEB128Value(const MCExpr *Value) override; void EmitDTPRel32Value(const MCExpr *Value) override; void EmitDTPRel64Value(const MCExpr *Value) override; void EmitTPRel32Value(const MCExpr *Value) override; void EmitTPRel64Value(const MCExpr *Value) override; void EmitGPRel64Value(const MCExpr *Value) override; void EmitGPRel32Value(const MCExpr *Value) override; void emitFill(const MCExpr &NumBytes, uint64_t FillValue, SMLoc Loc = SMLoc()) override; void emitFill(uint64_t NumValues, int64_t Size, int64_t Expr) override; void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, SMLoc Loc = SMLoc()) override; void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, unsigned ValueSize = 1, unsigned MaxBytesToEmit = 0) override; void EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit = 0) override; void emitValueToOffset(const MCExpr *Offset, unsigned char Value, SMLoc Loc) override; void EmitFileDirective(StringRef Filename) override; unsigned EmitDwarfFileDirective(unsigned FileNo, StringRef Directory, StringRef Filename, unsigned CUID = 0) override; void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column, unsigned Flags, unsigned Isa, unsigned Discriminator, StringRef FileName) override; MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override; bool EmitCVFileDirective(unsigned FileNo, StringRef Filename, ArrayRef Checksum, unsigned ChecksumKind) override; bool EmitCVFuncIdDirective(unsigned FuncId) override; bool EmitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc, unsigned IAFile, unsigned IALine, unsigned IACol, SMLoc Loc) override; void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt, StringRef FileName, SMLoc Loc) override; void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart, const MCSymbol *FnEnd) override; void EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, const MCSymbol *FnStartSym, const MCSymbol *FnEndSym) override; void EmitCVDefRangeDirective( ArrayRef> Ranges, 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; void EmitCFIDefCfa(int64_t Register, int64_t Offset) override; void EmitCFIDefCfaOffset(int64_t Offset) override; void EmitCFIDefCfaRegister(int64_t Register) override; void EmitCFIOffset(int64_t Register, int64_t Offset) override; void EmitCFIPersonality(const MCSymbol *Sym, unsigned Encoding) override; 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; void EmitCFIEscape(StringRef Values) override; void EmitCFIGnuArgsSize(int64_t Size) override; void EmitCFISignalFrame() override; 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 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; void EmitBundleAlignMode(unsigned AlignPow2) override; void EmitBundleLock(bool AlignToEnd) override; void EmitBundleUnlock() override; bool EmitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr, SMLoc Loc) override; /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. void EmitRawTextImpl(StringRef String) override; void FinishImpl() override; }; } // end anonymous namespace. /// AddComment - Add a comment that can be emitted to the generated .s /// file if applicable as a QoI issue to make the output of the compiler /// more readable. This only affects the MCAsmStreamer, and only when /// verbose assembly output is enabled. /// By deafult EOL is set to true so that each comment goes on its own line. void MCAsmStreamer::AddComment(const Twine &T, bool EOL) { if (!IsVerboseAsm) return; T.toVector(CommentToEmit); if (EOL) CommentToEmit.push_back('\n'); // Place comment in a new line. } void MCAsmStreamer::EmitCommentsAndEOL() { if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) { OS << '\n'; return; } StringRef Comments = CommentToEmit; assert(Comments.back() == '\n' && "Comment array not newline terminated"); do { // Emit a line of comments. OS.PadToColumn(MAI->getCommentColumn()); size_t Position = Comments.find('\n'); OS << MAI->getCommentString() << ' ' << Comments.substr(0, Position) <<'\n'; Comments = Comments.substr(Position+1); } while (!Comments.empty()); CommentToEmit.clear(); } static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) { assert(Bytes > 0 && Bytes <= 8 && "Invalid size!"); return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8)); } void MCAsmStreamer::emitRawComment(const Twine &T, bool TabPrefix) { if (TabPrefix) OS << '\t'; OS << MAI->getCommentString() << T; EmitEOL(); } void MCAsmStreamer::addExplicitComment(const Twine &T) { StringRef c = T.getSingleStringRef(); if (c.equals(StringRef(MAI->getSeparatorString()))) return; if (c.startswith(StringRef("//"))) { ExplicitCommentToEmit.append("\t"); ExplicitCommentToEmit.append(MAI->getCommentString()); // drop // ExplicitCommentToEmit.append(c.slice(2, c.size()).str()); } else if (c.startswith(StringRef("/*"))) { size_t p = 2, len = c.size() - 2; // emit each line in comment as separate newline. do { size_t newp = std::min(len, c.find_first_of("\r\n", p)); ExplicitCommentToEmit.append("\t"); ExplicitCommentToEmit.append(MAI->getCommentString()); ExplicitCommentToEmit.append(c.slice(p, newp).str()); // If we have another line in this comment add line if (newp < len) ExplicitCommentToEmit.append("\n"); p = newp + 1; } while (p < len); } else if (c.startswith(StringRef(MAI->getCommentString()))) { ExplicitCommentToEmit.append("\t"); ExplicitCommentToEmit.append(c.str()); } else if (c.front() == '#') { ExplicitCommentToEmit.append("\t"); ExplicitCommentToEmit.append(MAI->getCommentString()); ExplicitCommentToEmit.append(c.slice(1, c.size()).str()); } else assert(false && "Unexpected Assembly Comment"); // full line comments immediately output if (c.back() == '\n') emitExplicitComments(); } void MCAsmStreamer::emitExplicitComments() { StringRef Comments = ExplicitCommentToEmit; if (!Comments.empty()) OS << Comments; ExplicitCommentToEmit.clear(); } void MCAsmStreamer::ChangeSection(MCSection *Section, const MCExpr *Subsection) { assert(Section && "Cannot switch to a null section!"); if (MCTargetStreamer *TS = getTargetStreamer()) { TS->changeSection(getCurrentSectionOnly(), Section, Subsection, OS); } else { Section->PrintSwitchToSection( *MAI, getContext().getObjectFileInfo()->getTargetTriple(), OS, Subsection); } +} + +void MCAsmStreamer::emitELFSymverDirective(StringRef AliasName, + const MCSymbol *Aliasee) { + OS << ".symver "; + Aliasee->print(OS, MAI); + OS << ", " << AliasName; + EmitEOL(); } void MCAsmStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc) { MCStreamer::EmitLabel(Symbol, Loc); Symbol->print(OS, MAI); OS << MAI->getLabelSuffix(); EmitEOL(); } void MCAsmStreamer::EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) { StringRef str = MCLOHIdToName(Kind); #ifndef NDEBUG int NbArgs = MCLOHIdToNbArgs(Kind); assert(NbArgs != -1 && ((size_t)NbArgs) == Args.size() && "Malformed LOH!"); assert(str != "" && "Invalid LOH name"); #endif OS << "\t" << MCLOHDirectiveName() << " " << str << "\t"; bool IsFirst = true; for (const MCSymbol *Arg : Args) { if (!IsFirst) OS << ", "; IsFirst = false; Arg->print(OS, MAI); } EmitEOL(); } void MCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { switch (Flag) { case MCAF_SyntaxUnified: OS << "\t.syntax unified"; break; case MCAF_SubsectionsViaSymbols: OS << ".subsections_via_symbols"; break; case MCAF_Code16: OS << '\t'<< MAI->getCode16Directive();break; case MCAF_Code32: OS << '\t'<< MAI->getCode32Directive();break; case MCAF_Code64: OS << '\t'<< MAI->getCode64Directive();break; } EmitEOL(); } void MCAsmStreamer::EmitLinkerOptions(ArrayRef Options) { assert(!Options.empty() && "At least one option is required!"); OS << "\t.linker_option \"" << Options[0] << '"'; for (ArrayRef::iterator it = Options.begin() + 1, ie = Options.end(); it != ie; ++it) { OS << ", " << '"' << *it << '"'; } EmitEOL(); } void MCAsmStreamer::EmitDataRegion(MCDataRegionType Kind) { if (!MAI->doesSupportDataRegionDirectives()) return; switch (Kind) { case MCDR_DataRegion: OS << "\t.data_region"; break; case MCDR_DataRegionJT8: OS << "\t.data_region jt8"; break; case MCDR_DataRegionJT16: OS << "\t.data_region jt16"; break; case MCDR_DataRegionJT32: OS << "\t.data_region jt32"; break; case MCDR_DataRegionEnd: OS << "\t.end_data_region"; break; } EmitEOL(); } 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) { 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"; } 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(); } void MCAsmStreamer::EmitThumbFunc(MCSymbol *Func) { // This needs to emit to a temporary string to get properly quoted // MCSymbols when they have spaces in them. OS << "\t.thumb_func"; // Only Mach-O hasSubsectionsViaSymbols() if (MAI->hasSubsectionsViaSymbols()) { OS << '\t'; Func->print(OS, MAI); } EmitEOL(); } void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { Symbol->print(OS, MAI); OS << " = "; Value->print(OS, MAI); EmitEOL(); MCStreamer::EmitAssignment(Symbol, Value); } void MCAsmStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { OS << ".weakref "; Alias->print(OS, MAI); OS << ", "; Symbol->print(OS, MAI); EmitEOL(); } bool MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { switch (Attribute) { case MCSA_Invalid: llvm_unreachable("Invalid symbol attribute"); case MCSA_ELF_TypeFunction: /// .type _foo, STT_FUNC # aka @function case MCSA_ELF_TypeIndFunction: /// .type _foo, STT_GNU_IFUNC case MCSA_ELF_TypeObject: /// .type _foo, STT_OBJECT # aka @object case MCSA_ELF_TypeTLS: /// .type _foo, STT_TLS # aka @tls_object case MCSA_ELF_TypeCommon: /// .type _foo, STT_COMMON # aka @common case MCSA_ELF_TypeNoType: /// .type _foo, STT_NOTYPE # aka @notype case MCSA_ELF_TypeGnuUniqueObject: /// .type _foo, @gnu_unique_object if (!MAI->hasDotTypeDotSizeDirective()) return false; // Symbol attribute not supported OS << "\t.type\t"; Symbol->print(OS, MAI); OS << ',' << ((MAI->getCommentString()[0] != '@') ? '@' : '%'); switch (Attribute) { default: return false; case MCSA_ELF_TypeFunction: OS << "function"; break; case MCSA_ELF_TypeIndFunction: OS << "gnu_indirect_function"; break; case MCSA_ELF_TypeObject: OS << "object"; break; case MCSA_ELF_TypeTLS: OS << "tls_object"; break; case MCSA_ELF_TypeCommon: OS << "common"; break; case MCSA_ELF_TypeNoType: OS << "no_type"; break; case MCSA_ELF_TypeGnuUniqueObject: OS << "gnu_unique_object"; break; } EmitEOL(); return true; case MCSA_Global: // .globl/.global OS << MAI->getGlobalDirective(); break; case MCSA_Hidden: OS << "\t.hidden\t"; break; case MCSA_IndirectSymbol: OS << "\t.indirect_symbol\t"; break; case MCSA_Internal: OS << "\t.internal\t"; break; case MCSA_LazyReference: OS << "\t.lazy_reference\t"; break; case MCSA_Local: OS << "\t.local\t"; break; case MCSA_NoDeadStrip: if (!MAI->hasNoDeadStrip()) return false; OS << "\t.no_dead_strip\t"; break; case MCSA_SymbolResolver: OS << "\t.symbol_resolver\t"; break; case MCSA_AltEntry: OS << "\t.alt_entry\t"; break; case MCSA_PrivateExtern: OS << "\t.private_extern\t"; break; case MCSA_Protected: OS << "\t.protected\t"; break; case MCSA_Reference: OS << "\t.reference\t"; break; case MCSA_Weak: OS << MAI->getWeakDirective(); break; case MCSA_WeakDefinition: OS << "\t.weak_definition\t"; break; // .weak_reference case MCSA_WeakReference: OS << MAI->getWeakRefDirective(); break; case MCSA_WeakDefAutoPrivate: OS << "\t.weak_def_can_be_hidden\t"; break; } Symbol->print(OS, MAI); EmitEOL(); return true; } void MCAsmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { OS << ".desc" << ' '; Symbol->print(OS, MAI); OS << ',' << DescValue; EmitEOL(); } void MCAsmStreamer::EmitSyntaxDirective() { if (MAI->getAssemblerDialect() == 1) { OS << "\t.intel_syntax noprefix"; EmitEOL(); } // FIXME: Currently emit unprefix'ed registers. // The intel_syntax directive has one optional argument // with may have a value of prefix or noprefix. } void MCAsmStreamer::BeginCOFFSymbolDef(const MCSymbol *Symbol) { OS << "\t.def\t "; Symbol->print(OS, MAI); OS << ';'; EmitEOL(); } void MCAsmStreamer::EmitCOFFSymbolStorageClass (int StorageClass) { OS << "\t.scl\t" << StorageClass << ';'; EmitEOL(); } void MCAsmStreamer::EmitCOFFSymbolType (int Type) { OS << "\t.type\t" << Type << ';'; EmitEOL(); } void MCAsmStreamer::EndCOFFSymbolDef() { OS << "\t.endef"; EmitEOL(); } void MCAsmStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) { OS << "\t.safeseh\t"; Symbol->print(OS, MAI); EmitEOL(); } void MCAsmStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) { OS << "\t.secidx\t"; Symbol->print(OS, MAI); EmitEOL(); } void MCAsmStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) { OS << "\t.secrel32\t"; Symbol->print(OS, MAI); if (Offset != 0) OS << '+' << Offset; EmitEOL(); } void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { assert(MAI->hasDotTypeDotSizeDirective()); OS << "\t.size\t"; Symbol->print(OS, MAI); OS << ", "; Value->print(OS, MAI); EmitEOL(); } void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { OS << "\t.comm\t"; Symbol->print(OS, MAI); OS << ',' << Size; if (ByteAlignment != 0) { if (MAI->getCOMMDirectiveAlignmentIsInBytes()) OS << ',' << ByteAlignment; else OS << ',' << Log2_32(ByteAlignment); } EmitEOL(); } /// EmitLocalCommonSymbol - Emit a local common (.lcomm) symbol. /// /// @param Symbol - The common symbol to emit. /// @param Size - The size of the common symbol. void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlign) { OS << "\t.lcomm\t"; Symbol->print(OS, MAI); OS << ',' << Size; if (ByteAlign > 1) { switch (MAI->getLCOMMDirectiveAlignmentType()) { case LCOMM::NoAlignment: llvm_unreachable("alignment not supported on .lcomm!"); case LCOMM::ByteAlignment: OS << ',' << ByteAlign; break; case LCOMM::Log2Alignment: assert(isPowerOf2_32(ByteAlign) && "alignment must be a power of 2"); OS << ',' << Log2_32(ByteAlign); break; } } EmitEOL(); } void MCAsmStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { if (Symbol) AssignFragment(Symbol, &Section->getDummyFragment()); // Note: a .zerofill directive does not switch sections. OS << ".zerofill "; // This is a mach-o specific directive. const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section); OS << MOSection->getSegmentName() << "," << MOSection->getSectionName(); if (Symbol) { OS << ','; Symbol->print(OS, MAI); OS << ',' << Size; if (ByteAlignment != 0) OS << ',' << Log2_32(ByteAlignment); } EmitEOL(); } // .tbss sym, size, align // This depends that the symbol has already been mangled from the original, // e.g. _a. void MCAsmStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { AssignFragment(Symbol, &Section->getDummyFragment()); assert(Symbol && "Symbol shouldn't be NULL!"); // Instead of using the Section we'll just use the shortcut. // This is a mach-o specific directive and section. OS << ".tbss "; Symbol->print(OS, MAI); OS << ", " << Size; // Output align if we have it. We default to 1 so don't bother printing // that. if (ByteAlignment > 1) OS << ", " << Log2_32(ByteAlignment); EmitEOL(); } static inline char toOctal(int X) { return (X&7)+'0'; } static void PrintQuotedString(StringRef Data, raw_ostream &OS) { OS << '"'; for (unsigned i = 0, e = Data.size(); i != e; ++i) { unsigned char C = Data[i]; if (C == '"' || C == '\\') { OS << '\\' << (char)C; continue; } if (isprint((unsigned char)C)) { OS << (char)C; continue; } switch (C) { case '\b': OS << "\\b"; break; case '\f': OS << "\\f"; break; case '\n': OS << "\\n"; break; case '\r': OS << "\\r"; break; case '\t': OS << "\\t"; break; default: OS << '\\'; OS << toOctal(C >> 6); OS << toOctal(C >> 3); OS << toOctal(C >> 0); break; } } OS << '"'; } void MCAsmStreamer::EmitBytes(StringRef Data) { assert(getCurrentSectionOnly() && "Cannot emit contents before setting section!"); if (Data.empty()) return; // If only single byte is provided or no ascii or asciz directives is // supported, emit as vector of 8bits data. if (Data.size() == 1 || !(MAI->getAscizDirective() || MAI->getAsciiDirective())) { const char *Directive = MAI->getData8bitsDirective(); for (const unsigned char C : Data.bytes()) { OS << Directive << (unsigned)C; EmitEOL(); } return; } // If the data ends with 0 and the target supports .asciz, use it, otherwise // use .ascii if (MAI->getAscizDirective() && Data.back() == 0) { OS << MAI->getAscizDirective(); Data = Data.substr(0, Data.size()-1); } else { OS << MAI->getAsciiDirective(); } PrintQuotedString(Data, OS); EmitEOL(); } void MCAsmStreamer::EmitBinaryData(StringRef Data) { // This is binary data. Print it in a grid of hex bytes for readability. const size_t Cols = 4; for (size_t I = 0, EI = alignTo(Data.size(), Cols); I < EI; I += Cols) { size_t J = I, EJ = std::min(I + Cols, Data.size()); assert(EJ > 0); OS << MAI->getData8bitsDirective(); for (; J < EJ - 1; ++J) OS << format("0x%02x", uint8_t(Data[J])) << ", "; OS << format("0x%02x", uint8_t(Data[J])); EmitEOL(); } } void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size) { EmitValue(MCConstantExpr::create(Value, getContext()), Size); } void MCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) { assert(Size <= 8 && "Invalid size"); assert(getCurrentSectionOnly() && "Cannot emit contents before setting section!"); const char *Directive = nullptr; switch (Size) { default: break; case 1: Directive = MAI->getData8bitsDirective(); break; case 2: Directive = MAI->getData16bitsDirective(); break; case 4: Directive = MAI->getData32bitsDirective(); break; case 8: Directive = MAI->getData64bitsDirective(); break; } if (!Directive) { int64_t IntValue; if (!Value->evaluateAsAbsolute(IntValue)) report_fatal_error("Don't know how to emit this value."); // We couldn't handle the requested integer size so we fallback by breaking // the request down into several, smaller, integers. // Since sizes greater or equal to "Size" are invalid, we use the greatest // power of 2 that is less than "Size" as our largest piece of granularity. bool IsLittleEndian = MAI->isLittleEndian(); for (unsigned Emitted = 0; Emitted != Size;) { unsigned Remaining = Size - Emitted; // The size of our partial emission must be a power of two less than // Size. unsigned EmissionSize = PowerOf2Floor(std::min(Remaining, Size - 1)); // Calculate the byte offset of our partial emission taking into account // the endianness of the target. unsigned ByteOffset = IsLittleEndian ? Emitted : (Remaining - EmissionSize); uint64_t ValueToEmit = IntValue >> (ByteOffset * 8); // We truncate our partial emission to fit within the bounds of the // emission domain. This produces nicer output and silences potential // truncation warnings when round tripping through another assembler. uint64_t Shift = 64 - EmissionSize * 8; assert(Shift < static_cast( std::numeric_limits::digits) && "undefined behavior"); ValueToEmit &= ~0ULL >> Shift; EmitIntValue(ValueToEmit, EmissionSize); Emitted += EmissionSize; } return; } assert(Directive && "Invalid size for machine code value!"); OS << Directive; if (MCTargetStreamer *TS = getTargetStreamer()) { TS->emitValue(Value); } else { Value->print(OS, MAI); EmitEOL(); } } void MCAsmStreamer::EmitULEB128Value(const MCExpr *Value) { int64_t IntValue; if (Value->evaluateAsAbsolute(IntValue)) { EmitULEB128IntValue(IntValue); return; } OS << ".uleb128 "; Value->print(OS, MAI); EmitEOL(); } void MCAsmStreamer::EmitSLEB128Value(const MCExpr *Value) { int64_t IntValue; if (Value->evaluateAsAbsolute(IntValue)) { EmitSLEB128IntValue(IntValue); return; } OS << ".sleb128 "; Value->print(OS, MAI); EmitEOL(); } void MCAsmStreamer::EmitDTPRel64Value(const MCExpr *Value) { assert(MAI->getDTPRel64Directive() != nullptr); OS << MAI->getDTPRel64Directive(); Value->print(OS, MAI); EmitEOL(); } void MCAsmStreamer::EmitDTPRel32Value(const MCExpr *Value) { assert(MAI->getDTPRel32Directive() != nullptr); OS << MAI->getDTPRel32Directive(); Value->print(OS, MAI); EmitEOL(); } void MCAsmStreamer::EmitTPRel64Value(const MCExpr *Value) { assert(MAI->getTPRel64Directive() != nullptr); OS << MAI->getTPRel64Directive(); Value->print(OS, MAI); EmitEOL(); } void MCAsmStreamer::EmitTPRel32Value(const MCExpr *Value) { assert(MAI->getTPRel32Directive() != nullptr); OS << MAI->getTPRel32Directive(); Value->print(OS, MAI); EmitEOL(); } void MCAsmStreamer::EmitGPRel64Value(const MCExpr *Value) { assert(MAI->getGPRel64Directive() != nullptr); OS << MAI->getGPRel64Directive(); Value->print(OS, MAI); EmitEOL(); } void MCAsmStreamer::EmitGPRel32Value(const MCExpr *Value) { assert(MAI->getGPRel32Directive() != nullptr); OS << MAI->getGPRel32Directive(); Value->print(OS, MAI); EmitEOL(); } void MCAsmStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue, SMLoc Loc) { int64_t IntNumBytes; if (NumBytes.evaluateAsAbsolute(IntNumBytes) && IntNumBytes == 0) return; if (const char *ZeroDirective = MAI->getZeroDirective()) { // FIXME: Emit location directives OS << ZeroDirective; NumBytes.print(OS, MAI); if (FillValue != 0) OS << ',' << (int)FillValue; EmitEOL(); return; } MCStreamer::emitFill(NumBytes, FillValue); } void MCAsmStreamer::emitFill(uint64_t NumValues, int64_t Size, int64_t Expr) { if (NumValues == 0) return; const MCExpr *E = MCConstantExpr::create(NumValues, getContext()); emitFill(*E, Size, Expr); } void MCAsmStreamer::emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, SMLoc Loc) { // FIXME: Emit location directives OS << "\t.fill\t"; NumValues.print(OS, MAI); OS << ", " << Size << ", 0x"; OS.write_hex(truncateToSize(Expr, 4)); EmitEOL(); } void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { // Some assemblers don't support non-power of two alignments, so we always // emit alignments as a power of two if possible. if (isPowerOf2_32(ByteAlignment)) { switch (ValueSize) { default: llvm_unreachable("Invalid size for machine code value!"); case 1: OS << "\t.p2align\t"; break; case 2: OS << ".p2alignw "; break; case 4: OS << ".p2alignl "; break; case 8: llvm_unreachable("Unsupported alignment size!"); } OS << Log2_32(ByteAlignment); if (Value || MaxBytesToEmit) { OS << ", 0x"; OS.write_hex(truncateToSize(Value, ValueSize)); if (MaxBytesToEmit) OS << ", " << MaxBytesToEmit; } EmitEOL(); return; } // Non-power of two alignment. This is not widely supported by assemblers. // FIXME: Parameterize this based on MAI. switch (ValueSize) { default: llvm_unreachable("Invalid size for machine code value!"); case 1: OS << ".balign"; break; case 2: OS << ".balignw"; break; case 4: OS << ".balignl"; break; case 8: llvm_unreachable("Unsupported alignment size!"); } OS << ' ' << ByteAlignment; OS << ", " << truncateToSize(Value, ValueSize); if (MaxBytesToEmit) OS << ", " << MaxBytesToEmit; EmitEOL(); } void MCAsmStreamer::EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit) { // Emit with a text fill value. EmitValueToAlignment(ByteAlignment, MAI->getTextAlignFillValue(), 1, MaxBytesToEmit); } void MCAsmStreamer::emitValueToOffset(const MCExpr *Offset, unsigned char Value, SMLoc Loc) { // FIXME: Verify that Offset is associated with the current section. OS << ".org "; Offset->print(OS, MAI); OS << ", " << (unsigned)Value; EmitEOL(); } void MCAsmStreamer::EmitFileDirective(StringRef Filename) { assert(MAI->hasSingleParameterDotFile()); OS << "\t.file\t"; PrintQuotedString(Filename, OS); EmitEOL(); } unsigned MCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo, StringRef Directory, StringRef Filename, unsigned CUID) { assert(CUID == 0); MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID); unsigned NumFiles = Table.getMCDwarfFiles().size(); FileNo = Table.getFile(Directory, Filename, FileNo); if (FileNo == 0) return 0; if (NumFiles == Table.getMCDwarfFiles().size()) return FileNo; SmallString<128> FullPathName; if (!UseDwarfDirectory && !Directory.empty()) { if (sys::path::is_absolute(Filename)) Directory = ""; else { FullPathName = Directory; sys::path::append(FullPathName, Filename); Directory = ""; Filename = FullPathName; } } SmallString<128> Str; raw_svector_ostream OS1(Str); OS1 << "\t.file\t" << FileNo << ' '; if (!Directory.empty()) { PrintQuotedString(Directory, OS1); OS1 << ' '; } PrintQuotedString(Filename, OS1); if (MCTargetStreamer *TS = getTargetStreamer()) { TS->emitDwarfFileDirective(OS1.str()); } else { EmitRawText(OS1.str()); } return FileNo; } void MCAsmStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column, unsigned Flags, unsigned Isa, unsigned Discriminator, StringRef FileName) { OS << "\t.loc\t" << FileNo << " " << Line << " " << Column; if (Flags & DWARF2_FLAG_BASIC_BLOCK) OS << " basic_block"; if (Flags & DWARF2_FLAG_PROLOGUE_END) OS << " prologue_end"; if (Flags & DWARF2_FLAG_EPILOGUE_BEGIN) OS << " epilogue_begin"; unsigned OldFlags = getContext().getCurrentDwarfLoc().getFlags(); if ((Flags & DWARF2_FLAG_IS_STMT) != (OldFlags & DWARF2_FLAG_IS_STMT)) { OS << " is_stmt "; if (Flags & DWARF2_FLAG_IS_STMT) OS << "1"; else OS << "0"; } if (Isa) OS << " isa " << Isa; if (Discriminator) OS << " discriminator " << Discriminator; if (IsVerboseAsm) { OS.PadToColumn(MAI->getCommentColumn()); OS << MAI->getCommentString() << ' ' << FileName << ':' << Line << ':' << Column; } EmitEOL(); this->MCStreamer::EmitDwarfLocDirective(FileNo, Line, Column, Flags, Isa, Discriminator, FileName); } MCSymbol *MCAsmStreamer::getDwarfLineTableSymbol(unsigned CUID) { // Always use the zeroth line table, since asm syntax only supports one line // table for now. return MCStreamer::getDwarfLineTableSymbol(0); } bool MCAsmStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename, ArrayRef 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; } bool MCAsmStreamer::EmitCVFuncIdDirective(unsigned FuncId) { OS << "\t.cv_func_id " << FuncId << '\n'; return MCStreamer::EmitCVFuncIdDirective(FuncId); } bool MCAsmStreamer::EmitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc, unsigned IAFile, unsigned IALine, unsigned IACol, SMLoc Loc) { OS << "\t.cv_inline_site_id " << FunctionId << " within " << IAFunc << " inlined_at " << IAFile << ' ' << IALine << ' ' << IACol << '\n'; return MCStreamer::EmitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile, IALine, IACol, Loc); } void MCAsmStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt, StringRef FileName, SMLoc Loc) { OS << "\t.cv_loc\t" << FunctionId << " " << FileNo << " " << Line << " " << Column; if (PrologueEnd) OS << " prologue_end"; unsigned OldIsStmt = getContext().getCVContext().getCurrentCVLoc().isStmt(); if (IsStmt != OldIsStmt) { OS << " is_stmt "; if (IsStmt) OS << "1"; else OS << "0"; } if (IsVerboseAsm) { OS.PadToColumn(MAI->getCommentColumn()); OS << MAI->getCommentString() << ' ' << FileName << ':' << Line << ':' << Column; } EmitEOL(); this->MCStreamer::EmitCVLocDirective(FunctionId, FileNo, Line, Column, PrologueEnd, IsStmt, FileName, Loc); } void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart, const MCSymbol *FnEnd) { OS << "\t.cv_linetable\t" << FunctionId << ", "; FnStart->print(OS, MAI); OS << ", "; FnEnd->print(OS, MAI); EmitEOL(); this->MCStreamer::EmitCVLinetableDirective(FunctionId, FnStart, FnEnd); } void MCAsmStreamer::EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, const MCSymbol *FnStartSym, const MCSymbol *FnEndSym) { OS << "\t.cv_inline_linetable\t" << PrimaryFunctionId << ' ' << SourceFileId << ' ' << SourceLineNum << ' '; FnStartSym->print(OS, MAI); OS << ' '; FnEndSym->print(OS, MAI); EmitEOL(); this->MCStreamer::EmitCVInlineLinetableDirective( PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym); } void MCAsmStreamer::EmitCVDefRangeDirective( ArrayRef> Ranges, StringRef FixedSizePortion) { OS << "\t.cv_def_range\t"; for (std::pair Range : Ranges) { OS << ' '; Range.first->print(OS, MAI); OS << ' '; Range.second->print(OS, MAI); } OS << ", "; PrintQuotedString(FixedSizePortion, OS); EmitEOL(); this->MCStreamer::EmitCVDefRangeDirective(Ranges, FixedSizePortion); } void MCAsmStreamer::EmitCVStringTableDirective() { OS << "\t.cv_stringtable"; EmitEOL(); } void MCAsmStreamer::EmitCVFileChecksumsDirective() { OS << "\t.cv_filechecksums"; 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"; PrintQuotedString(IdentString, OS); EmitEOL(); } void MCAsmStreamer::EmitCFISections(bool EH, bool Debug) { MCStreamer::EmitCFISections(EH, Debug); OS << "\t.cfi_sections "; if (EH) { OS << ".eh_frame"; if (Debug) OS << ", .debug_frame"; } else if (Debug) { OS << ".debug_frame"; } EmitEOL(); } void MCAsmStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) { OS << "\t.cfi_startproc"; if (Frame.IsSimple) OS << " simple"; EmitEOL(); } void MCAsmStreamer::EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { MCStreamer::EmitCFIEndProcImpl(Frame); OS << "\t.cfi_endproc"; EmitEOL(); } 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(); int LLVMRegister = MRI->getLLVMRegNumFromEH(Register); if (LLVMRegister != -1) { InstPrinter->printRegName(OS, LLVMRegister); return; } } OS << Register; } void MCAsmStreamer::EmitCFIDefCfa(int64_t Register, int64_t Offset) { MCStreamer::EmitCFIDefCfa(Register, Offset); OS << "\t.cfi_def_cfa "; EmitRegisterName(Register); OS << ", " << Offset; EmitEOL(); } void MCAsmStreamer::EmitCFIDefCfaOffset(int64_t Offset) { MCStreamer::EmitCFIDefCfaOffset(Offset); OS << "\t.cfi_def_cfa_offset " << Offset; EmitEOL(); } static void PrintCFIEscape(llvm::formatted_raw_ostream &OS, StringRef Values) { OS << "\t.cfi_escape "; if (!Values.empty()) { size_t e = Values.size() - 1; for (size_t i = 0; i < e; ++i) OS << format("0x%02x", uint8_t(Values[i])) << ", "; OS << format("0x%02x", uint8_t(Values[e])); } } void MCAsmStreamer::EmitCFIEscape(StringRef Values) { MCStreamer::EmitCFIEscape(Values); PrintCFIEscape(OS, Values); EmitEOL(); } void MCAsmStreamer::EmitCFIGnuArgsSize(int64_t Size) { MCStreamer::EmitCFIGnuArgsSize(Size); uint8_t Buffer[16] = { dwarf::DW_CFA_GNU_args_size }; unsigned Len = encodeULEB128(Size, Buffer + 1) + 1; PrintCFIEscape(OS, StringRef((const char *)&Buffer[0], Len)); EmitEOL(); } void MCAsmStreamer::EmitCFIDefCfaRegister(int64_t Register) { MCStreamer::EmitCFIDefCfaRegister(Register); OS << "\t.cfi_def_cfa_register "; EmitRegisterName(Register); EmitEOL(); } void MCAsmStreamer::EmitCFIOffset(int64_t Register, int64_t Offset) { this->MCStreamer::EmitCFIOffset(Register, Offset); OS << "\t.cfi_offset "; EmitRegisterName(Register); OS << ", " << Offset; EmitEOL(); } void MCAsmStreamer::EmitCFIPersonality(const MCSymbol *Sym, unsigned Encoding) { MCStreamer::EmitCFIPersonality(Sym, Encoding); OS << "\t.cfi_personality " << Encoding << ", "; Sym->print(OS, MAI); EmitEOL(); } void MCAsmStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) { MCStreamer::EmitCFILsda(Sym, Encoding); OS << "\t.cfi_lsda " << Encoding << ", "; Sym->print(OS, MAI); EmitEOL(); } void MCAsmStreamer::EmitCFIRememberState() { MCStreamer::EmitCFIRememberState(); OS << "\t.cfi_remember_state"; EmitEOL(); } void MCAsmStreamer::EmitCFIRestoreState() { MCStreamer::EmitCFIRestoreState(); OS << "\t.cfi_restore_state"; 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 "; EmitRegisterName(Register); EmitEOL(); } void MCAsmStreamer::EmitCFIRelOffset(int64_t Register, int64_t Offset) { MCStreamer::EmitCFIRelOffset(Register, Offset); OS << "\t.cfi_rel_offset "; EmitRegisterName(Register); OS << ", " << Offset; EmitEOL(); } void MCAsmStreamer::EmitCFIAdjustCfaOffset(int64_t Adjustment) { MCStreamer::EmitCFIAdjustCfaOffset(Adjustment); OS << "\t.cfi_adjust_cfa_offset " << Adjustment; EmitEOL(); } void MCAsmStreamer::EmitCFISignalFrame() { MCStreamer::EmitCFISignalFrame(); OS << "\t.cfi_signal_frame"; EmitEOL(); } void MCAsmStreamer::EmitCFIUndefined(int64_t Register) { MCStreamer::EmitCFIUndefined(Register); OS << "\t.cfi_undefined " << Register; EmitEOL(); } void MCAsmStreamer::EmitCFIRegister(int64_t Register1, int64_t Register2) { MCStreamer::EmitCFIRegister(Register1, Register2); OS << "\t.cfi_register " << Register1 << ", " << Register2; EmitEOL(); } void MCAsmStreamer::EmitCFIWindowSave() { MCStreamer::EmitCFIWindowSave(); OS << "\t.cfi_window_save"; EmitEOL(); } 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(SMLoc Loc) { MCStreamer::EmitWinCFIEndProc(Loc); OS << "\t.seh_endproc"; EmitEOL(); } void MCAsmStreamer::EmitWinCFIStartChained(SMLoc Loc) { MCStreamer::EmitWinCFIStartChained(Loc); OS << "\t.seh_startchained"; EmitEOL(); } void MCAsmStreamer::EmitWinCFIEndChained(SMLoc Loc) { MCStreamer::EmitWinCFIEndChained(Loc); OS << "\t.seh_endchained"; EmitEOL(); } void MCAsmStreamer::EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except, SMLoc Loc) { MCStreamer::EmitWinEHHandler(Sym, Unwind, Except, Loc); OS << "\t.seh_handler "; Sym->print(OS, MAI); if (Unwind) OS << ", @unwind"; if (Except) OS << ", @except"; EmitEOL(); } 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. // We only do this so the section switch that terminates the handler // data block is visible. WinEH::FrameInfo *CurFrame = getCurrentWinFrameInfo(); MCSection *TextSec = &CurFrame->Function->getSection(); MCSection *XData = getAssociatedXDataSection(TextSec); SwitchSectionNoChange(XData); OS << "\t.seh_handlerdata"; EmitEOL(); } void MCAsmStreamer::EmitWinCFIPushReg(unsigned Register, SMLoc Loc) { MCStreamer::EmitWinCFIPushReg(Register, Loc); OS << "\t.seh_pushreg " << Register; EmitEOL(); } 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, SMLoc Loc) { MCStreamer::EmitWinCFIAllocStack(Size, Loc); OS << "\t.seh_stackalloc " << Size; EmitEOL(); } 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, SMLoc Loc) { MCStreamer::EmitWinCFISaveXMM(Register, Offset, Loc); OS << "\t.seh_savexmm " << Register << ", " << Offset; EmitEOL(); } void MCAsmStreamer::EmitWinCFIPushFrame(bool Code, SMLoc Loc) { MCStreamer::EmitWinCFIPushFrame(Code, Loc); OS << "\t.seh_pushframe"; if (Code) OS << " @code"; EmitEOL(); } void MCAsmStreamer::EmitWinCFIEndProlog(SMLoc Loc) { MCStreamer::EmitWinCFIEndProlog(Loc); OS << "\t.seh_endprologue"; EmitEOL(); } void MCAsmStreamer::AddEncodingComment(const MCInst &Inst, const MCSubtargetInfo &STI, bool PrintSchedInfo) { raw_ostream &OS = GetCommentOS(); SmallString<256> Code; SmallVector Fixups; raw_svector_ostream VecOS(Code); Emitter->encodeInstruction(Inst, VecOS, Fixups, STI); // If we are showing fixups, create symbolic markers in the encoded // representation. We do this by making a per-bit map to the fixup item index, // then trying to display it as nicely as possible. SmallVector FixupMap; FixupMap.resize(Code.size() * 8); for (unsigned i = 0, e = Code.size() * 8; i != e; ++i) FixupMap[i] = 0; for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { MCFixup &F = Fixups[i]; const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind()); for (unsigned j = 0; j != Info.TargetSize; ++j) { unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j; assert(Index < Code.size() * 8 && "Invalid offset in fixup!"); FixupMap[Index] = 1 + i; } } // FIXME: Note the fixup comments for Thumb2 are completely bogus since the // high order halfword of a 32-bit Thumb2 instruction is emitted first. OS << "encoding: ["; for (unsigned i = 0, e = Code.size(); i != e; ++i) { if (i) OS << ','; // See if all bits are the same map entry. uint8_t MapEntry = FixupMap[i * 8 + 0]; for (unsigned j = 1; j != 8; ++j) { if (FixupMap[i * 8 + j] == MapEntry) continue; MapEntry = uint8_t(~0U); break; } if (MapEntry != uint8_t(~0U)) { if (MapEntry == 0) { OS << format("0x%02x", uint8_t(Code[i])); } else { if (Code[i]) { // FIXME: Some of the 8 bits require fix up. OS << format("0x%02x", uint8_t(Code[i])) << '\'' << char('A' + MapEntry - 1) << '\''; } else OS << char('A' + MapEntry - 1); } } else { // Otherwise, write out in binary. OS << "0b"; for (unsigned j = 8; j--;) { unsigned Bit = (Code[i] >> j) & 1; unsigned FixupBit; if (MAI->isLittleEndian()) FixupBit = i * 8 + j; else FixupBit = i * 8 + (7-j); if (uint8_t MapEntry = FixupMap[FixupBit]) { assert(Bit == 0 && "Encoder wrote into fixed up bit!"); OS << char('A' + MapEntry - 1); } else OS << Bit; } } } OS << "]"; // 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"; for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { MCFixup &F = Fixups[i]; const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind()); OS << " fixup " << char('A' + i) << " - " << "offset: " << F.getOffset() << ", value: " << *F.getValue() << ", kind: " << Info.Name << "\n"; } } void MCAsmStreamer::EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, bool PrintSchedInfo) { assert(getCurrentSectionOnly() && "Cannot emit contents before setting section!"); // Show the encoding in a comment if we have a code emitter. if (Emitter) AddEncodingComment(Inst, STI, PrintSchedInfo); // Show the MCInst if enabled. if (ShowInst) { if (PrintSchedInfo) GetCommentOS() << "\n"; Inst.dump_pretty(GetCommentOS(), InstPrinter.get(), "\n "); GetCommentOS() << "\n"; } if(getTargetStreamer()) getTargetStreamer()->prettyPrintAsm(*InstPrinter, OS, Inst, STI); else InstPrinter->printInst(&Inst, OS, "", STI); if (PrintSchedInfo) { std::string SI = STI.getSchedInfoStr(Inst); if (!SI.empty()) GetCommentOS() << SI; } StringRef Comments = CommentToEmit; if (Comments.size() && Comments.back() != '\n') GetCommentOS() << "\n"; EmitEOL(); } void MCAsmStreamer::EmitBundleAlignMode(unsigned AlignPow2) { OS << "\t.bundle_align_mode " << AlignPow2; EmitEOL(); } void MCAsmStreamer::EmitBundleLock(bool AlignToEnd) { OS << "\t.bundle_lock"; if (AlignToEnd) OS << " align_to_end"; EmitEOL(); } void MCAsmStreamer::EmitBundleUnlock() { OS << "\t.bundle_unlock"; EmitEOL(); } bool MCAsmStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr, SMLoc) { OS << "\t.reloc "; Offset.print(OS, MAI); OS << ", " << Name; if (Expr) { OS << ", "; Expr->print(OS, MAI); } EmitEOL(); return false; } /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. void MCAsmStreamer::EmitRawTextImpl(StringRef String) { if (!String.empty() && String.back() == '\n') String = String.substr(0, String.size()-1); OS << String; EmitEOL(); } void MCAsmStreamer::FinishImpl() { // If we are generating dwarf for assembly source files dump out the sections. if (getContext().getGenDwarfForAssembly()) MCGenDwarfInfo::Emit(this); // Emit the label for the line table, if requested - since the rest of the // line table will be defined by .loc/.file directives, and not emitted // directly, the label is the only work required here. auto &Tables = getContext().getMCDwarfLineTables(); if (!Tables.empty()) { assert(Tables.size() == 1 && "asm output only supports one line table"); if (auto *Label = Tables.begin()->second.getLabel()) { SwitchSection(getContext().getObjectFileInfo()->getDwarfLineSection()); EmitLabel(Label); } } } MCStreamer *llvm::createAsmStreamer(MCContext &Context, std::unique_ptr OS, bool isVerboseAsm, bool useDwarfDirectory, MCInstPrinter *IP, MCCodeEmitter *CE, MCAsmBackend *MAB, bool ShowInst) { return new MCAsmStreamer(Context, std::move(OS), isVerboseAsm, useDwarfDirectory, IP, CE, MAB, ShowInst); } Index: head/contrib/llvm/lib/MC/MCELFStreamer.cpp =================================================================== --- head/contrib/llvm/lib/MC/MCELFStreamer.cpp (revision 331365) +++ head/contrib/llvm/lib/MC/MCELFStreamer.cpp (revision 331366) @@ -1,658 +1,663 @@ //===- lib/MC/MCELFStreamer.cpp - ELF Object Output -----------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file assembles .s files and emits ELF .o object files. // //===----------------------------------------------------------------------===// #include "llvm/MC/MCELFStreamer.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCFragment.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolELF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include #include using namespace llvm; MCELFStreamer::MCELFStreamer(MCContext &Context, std::unique_ptr TAB, raw_pwrite_stream &OS, std::unique_ptr Emitter) : MCObjectStreamer(Context, std::move(TAB), OS, std::move(Emitter)) {} bool MCELFStreamer::isBundleLocked() const { return getCurrentSectionOnly()->isBundleLocked(); } void MCELFStreamer::mergeFragment(MCDataFragment *DF, MCDataFragment *EF) { MCAssembler &Assembler = getAssembler(); if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) { uint64_t FSize = EF->getContents().size(); if (FSize > Assembler.getBundleAlignSize()) report_fatal_error("Fragment can't be larger than a bundle size"); uint64_t RequiredBundlePadding = computeBundlePadding( Assembler, EF, DF->getContents().size(), FSize); if (RequiredBundlePadding > UINT8_MAX) report_fatal_error("Padding cannot exceed 255 bytes"); if (RequiredBundlePadding > 0) { SmallString<256> Code; raw_svector_ostream VecOS(Code); { auto OW = Assembler.getBackend().createObjectWriter(VecOS); EF->setBundlePadding(static_cast(RequiredBundlePadding)); Assembler.writeFragmentPadding(*EF, FSize, OW.get()); } DF->getContents().append(Code.begin(), Code.end()); } } flushPendingLabels(DF, DF->getContents().size()); for (unsigned i = 0, e = EF->getFixups().size(); i != e; ++i) { EF->getFixups()[i].setOffset(EF->getFixups()[i].getOffset() + DF->getContents().size()); DF->getFixups().push_back(EF->getFixups()[i]); } DF->setHasInstructions(true); DF->getContents().append(EF->getContents().begin(), EF->getContents().end()); } void MCELFStreamer::InitSections(bool NoExecStack) { MCContext &Ctx = getContext(); SwitchSection(Ctx.getObjectFileInfo()->getTextSection()); EmitCodeAlignment(4); if (NoExecStack) SwitchSection(Ctx.getAsmInfo()->getNonexecutableStackSection(Ctx)); } void MCELFStreamer::EmitLabel(MCSymbol *S, SMLoc Loc) { auto *Symbol = cast(S); MCObjectStreamer::EmitLabel(Symbol, Loc); const MCSectionELF &Section = static_cast(*getCurrentSectionOnly()); if (Section.getFlags() & ELF::SHF_TLS) Symbol->setType(ELF::STT_TLS); } void MCELFStreamer::EmitLabel(MCSymbol *S, SMLoc Loc, MCFragment *F) { auto *Symbol = cast(S); MCObjectStreamer::EmitLabel(Symbol, Loc, F); const MCSectionELF &Section = static_cast(*getCurrentSectionOnly()); if (Section.getFlags() & ELF::SHF_TLS) Symbol->setType(ELF::STT_TLS); } void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { // Let the target do whatever target specific stuff it needs to do. getAssembler().getBackend().handleAssemblerFlag(Flag); // Do any generic stuff we need to do. switch (Flag) { case MCAF_SyntaxUnified: return; // no-op here. case MCAF_Code16: return; // Change parsing mode; no-op here. case MCAF_Code32: return; // Change parsing mode; no-op here. case MCAF_Code64: return; // Change parsing mode; no-op here. case MCAF_SubsectionsViaSymbols: getAssembler().setSubsectionsViaSymbols(true); return; } llvm_unreachable("invalid assembler flag!"); } // If bundle alignment is used and there are any instructions in the section, it // needs to be aligned to at least the bundle size. static void setSectionAlignmentForBundling(const MCAssembler &Assembler, MCSection *Section) { if (Section && Assembler.isBundlingEnabled() && Section->hasInstructions() && Section->getAlignment() < Assembler.getBundleAlignSize()) Section->setAlignment(Assembler.getBundleAlignSize()); } void MCELFStreamer::ChangeSection(MCSection *Section, const MCExpr *Subsection) { MCSection *CurSection = getCurrentSectionOnly(); if (CurSection && isBundleLocked()) report_fatal_error("Unterminated .bundle_lock when changing a section"); MCAssembler &Asm = getAssembler(); // Ensure the previous section gets aligned if necessary. setSectionAlignmentForBundling(Asm, CurSection); auto *SectionELF = static_cast(Section); const MCSymbol *Grp = SectionELF->getGroup(); if (Grp) Asm.registerSymbol(*Grp); changeSectionImpl(Section, Subsection); Asm.registerSymbol(*Section->getBeginSymbol()); } void MCELFStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { getAssembler().registerSymbol(*Symbol); const MCExpr *Value = MCSymbolRefExpr::create( Symbol, MCSymbolRefExpr::VK_WEAKREF, getContext()); Alias->setVariableValue(Value); } // When GNU as encounters more than one .type declaration for an object it seems // to use a mechanism similar to the one below to decide which type is actually // used in the object file. The greater of T1 and T2 is selected based on the // following ordering: // STT_NOTYPE < STT_OBJECT < STT_FUNC < STT_GNU_IFUNC < STT_TLS < anything else // If neither T1 < T2 nor T2 < T1 according to this ordering, use T2 (the user // provided type). static unsigned CombineSymbolTypes(unsigned T1, unsigned T2) { for (unsigned Type : {ELF::STT_NOTYPE, ELF::STT_OBJECT, ELF::STT_FUNC, ELF::STT_GNU_IFUNC, ELF::STT_TLS}) { if (T1 == Type) return T2; if (T2 == Type) return T1; } return T2; } bool MCELFStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { auto *Symbol = cast(S); // Indirect symbols are handled differently, to match how 'as' handles // them. This makes writing matching .o files easier. if (Attribute == MCSA_IndirectSymbol) { // Note that we intentionally cannot use the symbol data here; this is // important for matching the string table that 'as' generates. IndirectSymbolData ISD; ISD.Symbol = Symbol; ISD.Section = getCurrentSectionOnly(); getAssembler().getIndirectSymbols().push_back(ISD); return true; } // Adding a symbol attribute always introduces the symbol, note that an // important side effect of calling registerSymbol here is to register // the symbol with the assembler. getAssembler().registerSymbol(*Symbol); // The implementation of symbol attributes is designed to match 'as', but it // leaves much to desired. It doesn't really make sense to arbitrarily add and // remove flags, but 'as' allows this (in particular, see .desc). // // In the future it might be worth trying to make these operations more well // defined. switch (Attribute) { case MCSA_LazyReference: case MCSA_Reference: case MCSA_SymbolResolver: case MCSA_PrivateExtern: case MCSA_WeakDefinition: case MCSA_WeakDefAutoPrivate: case MCSA_Invalid: case MCSA_IndirectSymbol: return false; case MCSA_NoDeadStrip: // Ignore for now. break; case MCSA_ELF_TypeGnuUniqueObject: Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_OBJECT)); Symbol->setBinding(ELF::STB_GNU_UNIQUE); Symbol->setExternal(true); break; case MCSA_Global: Symbol->setBinding(ELF::STB_GLOBAL); Symbol->setExternal(true); break; case MCSA_WeakReference: case MCSA_Weak: Symbol->setBinding(ELF::STB_WEAK); Symbol->setExternal(true); break; case MCSA_Local: Symbol->setBinding(ELF::STB_LOCAL); Symbol->setExternal(false); break; case MCSA_ELF_TypeFunction: Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_FUNC)); break; case MCSA_ELF_TypeIndFunction: Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_GNU_IFUNC)); break; case MCSA_ELF_TypeObject: Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_OBJECT)); break; case MCSA_ELF_TypeTLS: Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_TLS)); break; case MCSA_ELF_TypeCommon: // TODO: Emit these as a common symbol. Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_OBJECT)); break; case MCSA_ELF_TypeNoType: Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_NOTYPE)); break; case MCSA_Protected: Symbol->setVisibility(ELF::STV_PROTECTED); break; case MCSA_Hidden: Symbol->setVisibility(ELF::STV_HIDDEN); break; case MCSA_Internal: Symbol->setVisibility(ELF::STV_INTERNAL); break; case MCSA_AltEntry: llvm_unreachable("ELF doesn't support the .alt_entry attribute"); } return true; } void MCELFStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size, unsigned ByteAlignment) { auto *Symbol = cast(S); getAssembler().registerSymbol(*Symbol); if (!Symbol->isBindingSet()) { Symbol->setBinding(ELF::STB_GLOBAL); Symbol->setExternal(true); } Symbol->setType(ELF::STT_OBJECT); if (Symbol->getBinding() == ELF::STB_LOCAL) { MCSection &Section = *getAssembler().getContext().getELFSection( ".bss", ELF::SHT_NOBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); MCSectionSubPair P = getCurrentSection(); SwitchSection(&Section); EmitValueToAlignment(ByteAlignment, 0, 1, 0); EmitLabel(Symbol); EmitZeros(Size); // Update the maximum alignment of the section if necessary. if (ByteAlignment > Section.getAlignment()) Section.setAlignment(ByteAlignment); SwitchSection(P.first, P.second); } else { if(Symbol->declareCommon(Size, ByteAlignment)) report_fatal_error("Symbol: " + Symbol->getName() + " redeclared as different type"); } cast(Symbol) ->setSize(MCConstantExpr::create(Size, getContext())); } void MCELFStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { cast(Symbol)->setSize(Value); } +void MCELFStreamer::emitELFSymverDirective(StringRef AliasName, + const MCSymbol *Aliasee) { + getAssembler().Symvers.push_back({AliasName, Aliasee}); +} + void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *S, uint64_t Size, unsigned ByteAlignment) { auto *Symbol = cast(S); // FIXME: Should this be caught and done earlier? getAssembler().registerSymbol(*Symbol); Symbol->setBinding(ELF::STB_LOCAL); Symbol->setExternal(false); EmitCommonSymbol(Symbol, Size, ByteAlignment); } void MCELFStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) { if (isBundleLocked()) report_fatal_error("Emitting values inside a locked bundle is forbidden"); fixSymbolsInTLSFixups(Value); MCObjectStreamer::EmitValueImpl(Value, Size, Loc); } void MCELFStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { if (isBundleLocked()) report_fatal_error("Emitting values inside a locked bundle is forbidden"); MCObjectStreamer::EmitValueToAlignment(ByteAlignment, Value, ValueSize, MaxBytesToEmit); } void MCELFStreamer::EmitIdent(StringRef IdentString) { MCSection *Comment = getAssembler().getContext().getELFSection( ".comment", ELF::SHT_PROGBITS, ELF::SHF_MERGE | ELF::SHF_STRINGS, 1, ""); PushSection(); SwitchSection(Comment); if (!SeenIdent) { EmitIntValue(0, 1); SeenIdent = true; } EmitBytes(IdentString); EmitIntValue(0, 1); PopSection(); } void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { switch (expr->getKind()) { case MCExpr::Target: cast(expr)->fixELFSymbolsInTLSFixups(getAssembler()); break; case MCExpr::Constant: break; case MCExpr::Binary: { const MCBinaryExpr *be = cast(expr); fixSymbolsInTLSFixups(be->getLHS()); fixSymbolsInTLSFixups(be->getRHS()); break; } case MCExpr::SymbolRef: { const MCSymbolRefExpr &symRef = *cast(expr); switch (symRef.getKind()) { default: return; case MCSymbolRefExpr::VK_GOTTPOFF: case MCSymbolRefExpr::VK_INDNTPOFF: case MCSymbolRefExpr::VK_NTPOFF: case MCSymbolRefExpr::VK_GOTNTPOFF: case MCSymbolRefExpr::VK_TLSGD: case MCSymbolRefExpr::VK_TLSLD: case MCSymbolRefExpr::VK_TLSLDM: case MCSymbolRefExpr::VK_TPOFF: case MCSymbolRefExpr::VK_TPREL: case MCSymbolRefExpr::VK_DTPOFF: case MCSymbolRefExpr::VK_DTPREL: case MCSymbolRefExpr::VK_PPC_DTPMOD: case MCSymbolRefExpr::VK_PPC_TPREL_LO: case MCSymbolRefExpr::VK_PPC_TPREL_HI: case MCSymbolRefExpr::VK_PPC_TPREL_HA: case MCSymbolRefExpr::VK_PPC_TPREL_HIGHER: case MCSymbolRefExpr::VK_PPC_TPREL_HIGHERA: case MCSymbolRefExpr::VK_PPC_TPREL_HIGHEST: case MCSymbolRefExpr::VK_PPC_TPREL_HIGHESTA: case MCSymbolRefExpr::VK_PPC_DTPREL_LO: case MCSymbolRefExpr::VK_PPC_DTPREL_HI: case MCSymbolRefExpr::VK_PPC_DTPREL_HA: case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHER: case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHERA: case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHEST: case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHESTA: case MCSymbolRefExpr::VK_PPC_GOT_TPREL: case MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO: case MCSymbolRefExpr::VK_PPC_GOT_TPREL_HI: case MCSymbolRefExpr::VK_PPC_GOT_TPREL_HA: case MCSymbolRefExpr::VK_PPC_GOT_DTPREL: case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_LO: case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_HI: case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_HA: case MCSymbolRefExpr::VK_PPC_TLS: case MCSymbolRefExpr::VK_PPC_GOT_TLSGD: case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_LO: case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HI: case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HA: case MCSymbolRefExpr::VK_PPC_TLSGD: case MCSymbolRefExpr::VK_PPC_GOT_TLSLD: case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_LO: case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HI: case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HA: case MCSymbolRefExpr::VK_PPC_TLSLD: break; } getAssembler().registerSymbol(symRef.getSymbol()); cast(symRef.getSymbol()).setType(ELF::STT_TLS); break; } case MCExpr::Unary: fixSymbolsInTLSFixups(cast(expr)->getSubExpr()); break; } } void MCELFStreamer::EmitInstToFragment(const MCInst &Inst, const MCSubtargetInfo &STI) { this->MCObjectStreamer::EmitInstToFragment(Inst, STI); MCRelaxableFragment &F = *cast(getCurrentFragment()); for (unsigned i = 0, e = F.getFixups().size(); i != e; ++i) fixSymbolsInTLSFixups(F.getFixups()[i].getValue()); } void MCELFStreamer::EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &STI) { MCAssembler &Assembler = getAssembler(); SmallVector Fixups; SmallString<256> Code; raw_svector_ostream VecOS(Code); Assembler.getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI); for (unsigned i = 0, e = Fixups.size(); i != e; ++i) fixSymbolsInTLSFixups(Fixups[i].getValue()); // There are several possibilities here: // // If bundling is disabled, append the encoded instruction to the current data // fragment (or create a new such fragment if the current fragment is not a // data fragment). // // If bundling is enabled: // - If we're not in a bundle-locked group, emit the instruction into a // fragment of its own. If there are no fixups registered for the // instruction, emit a MCCompactEncodedInstFragment. Otherwise, emit a // MCDataFragment. // - If we're in a bundle-locked group, append the instruction to the current // data fragment because we want all the instructions in a group to get into // the same fragment. Be careful not to do that for the first instruction in // the group, though. MCDataFragment *DF; if (Assembler.isBundlingEnabled()) { MCSection &Sec = *getCurrentSectionOnly(); if (Assembler.getRelaxAll() && isBundleLocked()) // If the -mc-relax-all flag is used and we are bundle-locked, we re-use // the current bundle group. DF = BundleGroups.back(); else if (Assembler.getRelaxAll() && !isBundleLocked()) // When not in a bundle-locked group and the -mc-relax-all flag is used, // we create a new temporary fragment which will be later merged into // the current fragment. DF = new MCDataFragment(); else if (isBundleLocked() && !Sec.isBundleGroupBeforeFirstInst()) // If we are bundle-locked, we re-use the current fragment. // The bundle-locking directive ensures this is a new data fragment. DF = cast(getCurrentFragment()); else if (!isBundleLocked() && Fixups.size() == 0) { // Optimize memory usage by emitting the instruction to a // MCCompactEncodedInstFragment when not in a bundle-locked group and // there are no fixups registered. MCCompactEncodedInstFragment *CEIF = new MCCompactEncodedInstFragment(); insert(CEIF); CEIF->getContents().append(Code.begin(), Code.end()); return; } else { DF = new MCDataFragment(); insert(DF); } if (Sec.getBundleLockState() == MCSection::BundleLockedAlignToEnd) { // If this fragment is for a group marked "align_to_end", set a flag // in the fragment. This can happen after the fragment has already been // created if there are nested bundle_align groups and an inner one // is the one marked align_to_end. DF->setAlignToBundleEnd(true); } // We're now emitting an instruction in a bundle group, so this flag has // to be turned off. Sec.setBundleGroupBeforeFirstInst(false); } else { DF = getOrCreateDataFragment(); } // Add the fixups and data. for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); DF->getFixups().push_back(Fixups[i]); } DF->setHasInstructions(true); DF->getContents().append(Code.begin(), Code.end()); if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) { if (!isBundleLocked()) { mergeFragment(getOrCreateDataFragment(), DF); delete DF; } } } void MCELFStreamer::EmitBundleAlignMode(unsigned AlignPow2) { assert(AlignPow2 <= 30 && "Invalid bundle alignment"); MCAssembler &Assembler = getAssembler(); if (AlignPow2 > 0 && (Assembler.getBundleAlignSize() == 0 || Assembler.getBundleAlignSize() == 1U << AlignPow2)) Assembler.setBundleAlignSize(1U << AlignPow2); else report_fatal_error(".bundle_align_mode cannot be changed once set"); } void MCELFStreamer::EmitBundleLock(bool AlignToEnd) { MCSection &Sec = *getCurrentSectionOnly(); // Sanity checks // if (!getAssembler().isBundlingEnabled()) report_fatal_error(".bundle_lock forbidden when bundling is disabled"); if (!isBundleLocked()) Sec.setBundleGroupBeforeFirstInst(true); if (getAssembler().getRelaxAll() && !isBundleLocked()) { // TODO: drop the lock state and set directly in the fragment MCDataFragment *DF = new MCDataFragment(); BundleGroups.push_back(DF); } Sec.setBundleLockState(AlignToEnd ? MCSection::BundleLockedAlignToEnd : MCSection::BundleLocked); } void MCELFStreamer::EmitBundleUnlock() { MCSection &Sec = *getCurrentSectionOnly(); // Sanity checks if (!getAssembler().isBundlingEnabled()) report_fatal_error(".bundle_unlock forbidden when bundling is disabled"); else if (!isBundleLocked()) report_fatal_error(".bundle_unlock without matching lock"); else if (Sec.isBundleGroupBeforeFirstInst()) report_fatal_error("Empty bundle-locked group is forbidden"); // When the -mc-relax-all flag is used, we emit instructions to fragments // stored on a stack. When the bundle unlock is emitted, we pop a fragment // from the stack a merge it to the one below. if (getAssembler().getRelaxAll()) { assert(!BundleGroups.empty() && "There are no bundle groups"); MCDataFragment *DF = BundleGroups.back(); // FIXME: Use BundleGroups to track the lock state instead. Sec.setBundleLockState(MCSection::NotBundleLocked); // FIXME: Use more separate fragments for nested groups. if (!isBundleLocked()) { mergeFragment(getOrCreateDataFragment(), DF); BundleGroups.pop_back(); delete DF; } if (Sec.getBundleLockState() != MCSection::BundleLockedAlignToEnd) getOrCreateDataFragment()->setAlignToBundleEnd(false); } else Sec.setBundleLockState(MCSection::NotBundleLocked); } void MCELFStreamer::FinishImpl() { // Ensure the last section gets aligned if necessary. MCSection *CurSection = getCurrentSectionOnly(); setSectionAlignmentForBundling(getAssembler(), CurSection); EmitFrames(nullptr); this->MCObjectStreamer::FinishImpl(); } void MCELFStreamer::EmitThumbFunc(MCSymbol *Func) { llvm_unreachable("Generic ELF doesn't support this directive"); } void MCELFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { llvm_unreachable("ELF doesn't support this directive"); } void MCELFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { llvm_unreachable("ELF doesn't support this directive"); } void MCELFStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { llvm_unreachable("ELF doesn't support this directive"); } MCStreamer *llvm::createELFStreamer(MCContext &Context, std::unique_ptr &&MAB, raw_pwrite_stream &OS, std::unique_ptr &&CE, bool RelaxAll) { MCELFStreamer *S = new MCELFStreamer(Context, std::move(MAB), OS, std::move(CE)); if (RelaxAll) S->getAssembler().setRelaxAll(true); return S; } Index: head/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp =================================================================== --- head/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp (revision 331365) +++ head/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp (revision 331366) @@ -1,851 +1,847 @@ //===- ELFAsmParser.cpp - ELF Assembly Parser -----------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCAsmParserExtension.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolELF.h" #include "llvm/MC/SectionKind.h" #include "llvm/Support/Casting.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SMLoc.h" #include #include #include using namespace llvm; namespace { class ELFAsmParser : public MCAsmParserExtension { template void addDirectiveHandler(StringRef Directive) { MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( this, HandleDirective); getParser().addDirectiveHandler(Directive, Handler); } bool ParseSectionSwitch(StringRef Section, unsigned Type, unsigned Flags, SectionKind Kind); public: ELFAsmParser() { BracketExpressionsSupported = true; } void Initialize(MCAsmParser &Parser) override { // Call the base implementation. this->MCAsmParserExtension::Initialize(Parser); addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveData>(".data"); addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveText>(".text"); addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveBSS>(".bss"); addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveRoData>(".rodata"); addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveTData>(".tdata"); addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveTBSS>(".tbss"); addDirectiveHandler< &ELFAsmParser::ParseSectionDirectiveDataRel>(".data.rel"); addDirectiveHandler< &ELFAsmParser::ParseSectionDirectiveDataRelRo>(".data.rel.ro"); addDirectiveHandler< &ELFAsmParser::ParseSectionDirectiveEhFrame>(".eh_frame"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveSection>(".section"); addDirectiveHandler< &ELFAsmParser::ParseDirectivePushSection>(".pushsection"); addDirectiveHandler<&ELFAsmParser::ParseDirectivePopSection>(".popsection"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveSize>(".size"); addDirectiveHandler<&ELFAsmParser::ParseDirectivePrevious>(".previous"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveType>(".type"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveIdent>(".ident"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymver>(".symver"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveVersion>(".version"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveWeakref>(".weakref"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymbolAttribute>(".local"); addDirectiveHandler< &ELFAsmParser::ParseDirectiveSymbolAttribute>(".protected"); addDirectiveHandler< &ELFAsmParser::ParseDirectiveSymbolAttribute>(".internal"); addDirectiveHandler< &ELFAsmParser::ParseDirectiveSymbolAttribute>(".hidden"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveSubsection>(".subsection"); } // FIXME: Part of this logic is duplicated in the MCELFStreamer. What is // the best way for us to get access to it? bool ParseSectionDirectiveData(StringRef, SMLoc) { return ParseSectionSwitch(".data", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC, SectionKind::getData()); } bool ParseSectionDirectiveText(StringRef, SMLoc) { return ParseSectionSwitch(".text", ELF::SHT_PROGBITS, ELF::SHF_EXECINSTR | ELF::SHF_ALLOC, SectionKind::getText()); } bool ParseSectionDirectiveBSS(StringRef, SMLoc) { return ParseSectionSwitch(".bss", ELF::SHT_NOBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC, SectionKind::getBSS()); } bool ParseSectionDirectiveRoData(StringRef, SMLoc) { return ParseSectionSwitch(".rodata", ELF::SHT_PROGBITS, ELF::SHF_ALLOC, SectionKind::getReadOnly()); } bool ParseSectionDirectiveTData(StringRef, SMLoc) { return ParseSectionSwitch(".tdata", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_TLS | ELF::SHF_WRITE, SectionKind::getThreadData()); } bool ParseSectionDirectiveTBSS(StringRef, SMLoc) { return ParseSectionSwitch(".tbss", ELF::SHT_NOBITS, ELF::SHF_ALLOC | ELF::SHF_TLS | ELF::SHF_WRITE, SectionKind::getThreadBSS()); } bool ParseSectionDirectiveDataRel(StringRef, SMLoc) { return ParseSectionSwitch(".data.rel", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_WRITE, SectionKind::getData()); } bool ParseSectionDirectiveDataRelRo(StringRef, SMLoc) { return ParseSectionSwitch(".data.rel.ro", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_WRITE, SectionKind::getReadOnlyWithRel()); } bool ParseSectionDirectiveEhFrame(StringRef, SMLoc) { return ParseSectionSwitch(".eh_frame", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_WRITE, SectionKind::getData()); } bool ParseDirectivePushSection(StringRef, SMLoc); bool ParseDirectivePopSection(StringRef, SMLoc); bool ParseDirectiveSection(StringRef, SMLoc); bool ParseDirectiveSize(StringRef, SMLoc); bool ParseDirectivePrevious(StringRef, SMLoc); bool ParseDirectiveType(StringRef, SMLoc); bool ParseDirectiveIdent(StringRef, SMLoc); bool ParseDirectiveSymver(StringRef, SMLoc); bool ParseDirectiveVersion(StringRef, SMLoc); bool ParseDirectiveWeakref(StringRef, SMLoc); bool ParseDirectiveSymbolAttribute(StringRef, SMLoc); bool ParseDirectiveSubsection(StringRef, SMLoc); private: bool ParseSectionName(StringRef &SectionName); bool ParseSectionArguments(bool IsPush, SMLoc loc); unsigned parseSunStyleSectionFlags(); bool maybeParseSectionType(StringRef &TypeName); bool parseMergeSize(int64_t &Size); bool parseGroup(StringRef &GroupName); bool parseMetadataSym(MCSymbolELF *&Associated); bool maybeParseUniqueID(int64_t &UniqueID); }; } // end anonymous namespace /// ParseDirectiveSymbolAttribute /// ::= { ".local", ".weak", ... } [ identifier ( , identifier )* ] bool ELFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { MCSymbolAttr Attr = StringSwitch(Directive) .Case(".weak", MCSA_Weak) .Case(".local", MCSA_Local) .Case(".hidden", MCSA_Hidden) .Case(".internal", MCSA_Internal) .Case(".protected", MCSA_Protected) .Default(MCSA_Invalid); assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); if (getLexer().isNot(AsmToken::EndOfStatement)) { while (true) { StringRef Name; if (getParser().parseIdentifier(Name)) return TokError("expected identifier in directive"); MCSymbol *Sym = getContext().getOrCreateSymbol(Name); getStreamer().EmitSymbolAttribute(Sym, Attr); if (getLexer().is(AsmToken::EndOfStatement)) break; if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in directive"); Lex(); } } Lex(); return false; } bool ELFAsmParser::ParseSectionSwitch(StringRef Section, unsigned Type, unsigned Flags, SectionKind Kind) { const MCExpr *Subsection = nullptr; if (getLexer().isNot(AsmToken::EndOfStatement)) { if (getParser().parseExpression(Subsection)) return true; } Lex(); getStreamer().SwitchSection(getContext().getELFSection(Section, Type, Flags), Subsection); return false; } bool ELFAsmParser::ParseDirectiveSize(StringRef, SMLoc) { StringRef Name; if (getParser().parseIdentifier(Name)) return TokError("expected identifier in directive"); MCSymbolELF *Sym = cast(getContext().getOrCreateSymbol(Name)); if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in directive"); Lex(); const MCExpr *Expr; if (getParser().parseExpression(Expr)) return true; if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in directive"); Lex(); getStreamer().emitELFSize(Sym, Expr); return false; } bool ELFAsmParser::ParseSectionName(StringRef &SectionName) { // A section name can contain -, so we cannot just use // parseIdentifier. SMLoc FirstLoc = getLexer().getLoc(); unsigned Size = 0; if (getLexer().is(AsmToken::String)) { SectionName = getTok().getIdentifier(); Lex(); return false; } while (!getParser().hasPendingError()) { SMLoc PrevLoc = getLexer().getLoc(); if (getLexer().is(AsmToken::Comma) || getLexer().is(AsmToken::EndOfStatement)) break; unsigned CurSize; if (getLexer().is(AsmToken::String)) { CurSize = getTok().getIdentifier().size() + 2; Lex(); } else if (getLexer().is(AsmToken::Identifier)) { CurSize = getTok().getIdentifier().size(); Lex(); } else { CurSize = getTok().getString().size(); Lex(); } Size += CurSize; SectionName = StringRef(FirstLoc.getPointer(), Size); // Make sure the following token is adjacent. if (PrevLoc.getPointer() + CurSize != getTok().getLoc().getPointer()) break; } if (Size == 0) return true; return false; } static unsigned parseSectionFlags(StringRef flagsStr, bool *UseLastGroup) { unsigned flags = 0; // If a valid numerical value is set for the section flag, use it verbatim if (!flagsStr.getAsInteger(0, flags)) return flags; for (char i : flagsStr) { switch (i) { case 'a': flags |= ELF::SHF_ALLOC; break; case 'e': flags |= ELF::SHF_EXCLUDE; break; case 'x': flags |= ELF::SHF_EXECINSTR; break; case 'w': flags |= ELF::SHF_WRITE; break; case 'o': flags |= ELF::SHF_LINK_ORDER; break; case 'M': flags |= ELF::SHF_MERGE; break; case 'S': flags |= ELF::SHF_STRINGS; break; case 'T': flags |= ELF::SHF_TLS; break; case 'c': flags |= ELF::XCORE_SHF_CP_SECTION; break; case 'd': flags |= ELF::XCORE_SHF_DP_SECTION; break; case 'y': flags |= ELF::SHF_ARM_PURECODE; break; case 'G': flags |= ELF::SHF_GROUP; break; case '?': *UseLastGroup = true; break; default: return -1U; } } return flags; } unsigned ELFAsmParser::parseSunStyleSectionFlags() { unsigned flags = 0; while (getLexer().is(AsmToken::Hash)) { Lex(); // Eat the #. if (!getLexer().is(AsmToken::Identifier)) return -1U; StringRef flagId = getTok().getIdentifier(); if (flagId == "alloc") flags |= ELF::SHF_ALLOC; else if (flagId == "execinstr") flags |= ELF::SHF_EXECINSTR; else if (flagId == "write") flags |= ELF::SHF_WRITE; else if (flagId == "tls") flags |= ELF::SHF_TLS; else return -1U; Lex(); // Eat the flag. if (!getLexer().is(AsmToken::Comma)) break; Lex(); // Eat the comma. } return flags; } bool ELFAsmParser::ParseDirectivePushSection(StringRef s, SMLoc loc) { getStreamer().PushSection(); if (ParseSectionArguments(/*IsPush=*/true, loc)) { getStreamer().PopSection(); return true; } return false; } bool ELFAsmParser::ParseDirectivePopSection(StringRef, SMLoc) { if (!getStreamer().PopSection()) return TokError(".popsection without corresponding .pushsection"); return false; } // FIXME: This is a work in progress. bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc loc) { return ParseSectionArguments(/*IsPush=*/false, loc); } bool ELFAsmParser::maybeParseSectionType(StringRef &TypeName) { MCAsmLexer &L = getLexer(); if (L.isNot(AsmToken::Comma)) return false; Lex(); if (L.isNot(AsmToken::At) && L.isNot(AsmToken::Percent) && L.isNot(AsmToken::String)) { if (L.getAllowAtInIdentifier()) return TokError("expected '@', '%' or \"\""); else return TokError("expected '%' or \"\""); } if (!L.is(AsmToken::String)) Lex(); if (L.is(AsmToken::Integer)) { TypeName = getTok().getString(); Lex(); } else if (getParser().parseIdentifier(TypeName)) return TokError("expected identifier in directive"); return false; } bool ELFAsmParser::parseMergeSize(int64_t &Size) { if (getLexer().isNot(AsmToken::Comma)) return TokError("expected the entry size"); Lex(); if (getParser().parseAbsoluteExpression(Size)) return true; if (Size <= 0) return TokError("entry size must be positive"); return false; } bool ELFAsmParser::parseGroup(StringRef &GroupName) { MCAsmLexer &L = getLexer(); if (L.isNot(AsmToken::Comma)) return TokError("expected group name"); Lex(); if (L.is(AsmToken::Integer)) { GroupName = getTok().getString(); Lex(); } else if (getParser().parseIdentifier(GroupName)) { return TokError("invalid group name"); } if (L.is(AsmToken::Comma)) { Lex(); StringRef Linkage; if (getParser().parseIdentifier(Linkage)) return TokError("invalid linkage"); if (Linkage != "comdat") return TokError("Linkage must be 'comdat'"); } return false; } bool ELFAsmParser::parseMetadataSym(MCSymbolELF *&Associated) { MCAsmLexer &L = getLexer(); if (L.isNot(AsmToken::Comma)) return TokError("expected metadata symbol"); Lex(); StringRef Name; if (getParser().parseIdentifier(Name)) return TokError("invalid metadata symbol"); Associated = dyn_cast_or_null(getContext().lookupSymbol(Name)); if (!Associated || !Associated->isInSection()) return TokError("symbol is not in a section: " + Name); return false; } bool ELFAsmParser::maybeParseUniqueID(int64_t &UniqueID) { MCAsmLexer &L = getLexer(); if (L.isNot(AsmToken::Comma)) return false; Lex(); StringRef UniqueStr; if (getParser().parseIdentifier(UniqueStr)) return TokError("expected identifier in directive"); if (UniqueStr != "unique") return TokError("expected 'unique'"); if (L.isNot(AsmToken::Comma)) return TokError("expected commma"); Lex(); if (getParser().parseAbsoluteExpression(UniqueID)) return true; if (UniqueID < 0) return TokError("unique id must be positive"); if (!isUInt<32>(UniqueID) || UniqueID == ~0U) return TokError("unique id is too large"); return false; } static bool hasPrefix(StringRef SectionName, StringRef Prefix) { return SectionName.startswith(Prefix) || SectionName == Prefix.drop_back(); } bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) { StringRef SectionName; if (ParseSectionName(SectionName)) return TokError("expected identifier in directive"); StringRef TypeName; int64_t Size = 0; StringRef GroupName; unsigned Flags = 0; const MCExpr *Subsection = nullptr; bool UseLastGroup = false; MCSymbolELF *Associated = nullptr; int64_t UniqueID = ~0; // Set the defaults first. if (hasPrefix(SectionName, ".rodata.") || SectionName == ".rodata1") Flags |= ELF::SHF_ALLOC; if (SectionName == ".fini" || SectionName == ".init" || hasPrefix(SectionName, ".text.")) Flags |= ELF::SHF_ALLOC | ELF::SHF_EXECINSTR; if (hasPrefix(SectionName, ".data.") || SectionName == ".data1" || hasPrefix(SectionName, ".bss.") || hasPrefix(SectionName, ".init_array.") || hasPrefix(SectionName, ".fini_array.") || hasPrefix(SectionName, ".preinit_array.")) Flags |= ELF::SHF_ALLOC | ELF::SHF_WRITE; if (hasPrefix(SectionName, ".tdata.") || hasPrefix(SectionName, ".tbss.")) Flags |= ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_TLS; if (getLexer().is(AsmToken::Comma)) { Lex(); if (IsPush && getLexer().isNot(AsmToken::String)) { if (getParser().parseExpression(Subsection)) return true; if (getLexer().isNot(AsmToken::Comma)) goto EndStmt; Lex(); } unsigned extraFlags; if (getLexer().isNot(AsmToken::String)) { if (!getContext().getAsmInfo()->usesSunStyleELFSectionSwitchSyntax() || getLexer().isNot(AsmToken::Hash)) return TokError("expected string in directive"); extraFlags = parseSunStyleSectionFlags(); } else { StringRef FlagsStr = getTok().getStringContents(); Lex(); extraFlags = parseSectionFlags(FlagsStr, &UseLastGroup); } if (extraFlags == -1U) return TokError("unknown flag"); Flags |= extraFlags; bool Mergeable = Flags & ELF::SHF_MERGE; bool Group = Flags & ELF::SHF_GROUP; if (Group && UseLastGroup) return TokError("Section cannot specifiy a group name while also acting " "as a member of the last group"); if (maybeParseSectionType(TypeName)) return true; MCAsmLexer &L = getLexer(); if (TypeName.empty()) { if (Mergeable) return TokError("Mergeable section must specify the type"); if (Group) return TokError("Group section must specify the type"); if (L.isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in directive"); } if (Mergeable) if (parseMergeSize(Size)) return true; if (Group) if (parseGroup(GroupName)) return true; if (Flags & ELF::SHF_LINK_ORDER) if (parseMetadataSym(Associated)) return true; if (maybeParseUniqueID(UniqueID)) return true; } EndStmt: if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in directive"); Lex(); unsigned Type = ELF::SHT_PROGBITS; if (TypeName.empty()) { if (SectionName.startswith(".note")) Type = ELF::SHT_NOTE; else if (hasPrefix(SectionName, ".init_array.")) Type = ELF::SHT_INIT_ARRAY; else if (hasPrefix(SectionName, ".bss.")) Type = ELF::SHT_NOBITS; else if (hasPrefix(SectionName, ".tbss.")) Type = ELF::SHT_NOBITS; else if (hasPrefix(SectionName, ".fini_array.")) Type = ELF::SHT_FINI_ARRAY; else if (hasPrefix(SectionName, ".preinit_array.")) Type = ELF::SHT_PREINIT_ARRAY; } else { if (TypeName == "init_array") Type = ELF::SHT_INIT_ARRAY; else if (TypeName == "fini_array") Type = ELF::SHT_FINI_ARRAY; else if (TypeName == "preinit_array") Type = ELF::SHT_PREINIT_ARRAY; else if (TypeName == "nobits") Type = ELF::SHT_NOBITS; else if (TypeName == "progbits") Type = ELF::SHT_PROGBITS; else if (TypeName == "note") Type = ELF::SHT_NOTE; else if (TypeName == "unwind") Type = ELF::SHT_X86_64_UNWIND; else if (TypeName == "llvm_odrtab") Type = ELF::SHT_LLVM_ODRTAB; else if (TypeName.getAsInteger(0, Type)) return TokError("unknown section type"); } if (UseLastGroup) { MCSectionSubPair CurrentSection = getStreamer().getCurrentSection(); if (const MCSectionELF *Section = cast_or_null(CurrentSection.first)) if (const MCSymbol *Group = Section->getGroup()) { GroupName = Group->getName(); Flags |= ELF::SHF_GROUP; } } MCSection *ELFSection = getContext().getELFSection(SectionName, Type, Flags, Size, GroupName, UniqueID, Associated); getStreamer().SwitchSection(ELFSection, Subsection); if (getContext().getGenDwarfForAssembly()) { bool InsertResult = getContext().addGenDwarfSection(ELFSection); if (InsertResult) { if (getContext().getDwarfVersion() <= 2) Warning(loc, "DWARF2 only supports one section per compilation unit"); if (!ELFSection->getBeginSymbol()) { MCSymbol *SectionStartSymbol = getContext().createTempSymbol(); getStreamer().EmitLabel(SectionStartSymbol); ELFSection->setBeginSymbol(SectionStartSymbol); } } } return false; } bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName, SMLoc) { MCSectionSubPair PreviousSection = getStreamer().getPreviousSection(); if (PreviousSection.first == nullptr) return TokError(".previous without corresponding .section"); getStreamer().SwitchSection(PreviousSection.first, PreviousSection.second); return false; } static MCSymbolAttr MCAttrForString(StringRef Type) { return StringSwitch(Type) .Cases("STT_FUNC", "function", MCSA_ELF_TypeFunction) .Cases("STT_OBJECT", "object", MCSA_ELF_TypeObject) .Cases("STT_TLS", "tls_object", MCSA_ELF_TypeTLS) .Cases("STT_COMMON", "common", MCSA_ELF_TypeCommon) .Cases("STT_NOTYPE", "notype", MCSA_ELF_TypeNoType) .Cases("STT_GNU_IFUNC", "gnu_indirect_function", MCSA_ELF_TypeIndFunction) .Case("gnu_unique_object", MCSA_ELF_TypeGnuUniqueObject) .Default(MCSA_Invalid); } /// ParseDirectiveELFType /// ::= .type identifier , STT_ /// ::= .type identifier , #attribute /// ::= .type identifier , @attribute /// ::= .type identifier , %attribute /// ::= .type identifier , "attribute" bool ELFAsmParser::ParseDirectiveType(StringRef, SMLoc) { StringRef Name; if (getParser().parseIdentifier(Name)) return TokError("expected identifier in directive"); // Handle the identifier as the key symbol. MCSymbol *Sym = getContext().getOrCreateSymbol(Name); // NOTE the comma is optional in all cases. It is only documented as being // optional in the first case, however, GAS will silently treat the comma as // optional in all cases. Furthermore, although the documentation states that // the first form only accepts STT_, in reality, GAS // accepts both the upper case name as well as the lower case aliases. if (getLexer().is(AsmToken::Comma)) Lex(); if (getLexer().isNot(AsmToken::Identifier) && getLexer().isNot(AsmToken::Hash) && getLexer().isNot(AsmToken::Percent) && getLexer().isNot(AsmToken::String)) { if (!getLexer().getAllowAtInIdentifier()) return TokError("expected STT_, '#', " "'%' or \"\""); else if (getLexer().isNot(AsmToken::At)) return TokError("expected STT_, '#', '@', " "'%' or \"\""); } if (getLexer().isNot(AsmToken::String) && getLexer().isNot(AsmToken::Identifier)) Lex(); SMLoc TypeLoc = getLexer().getLoc(); StringRef Type; if (getParser().parseIdentifier(Type)) return TokError("expected symbol type in directive"); MCSymbolAttr Attr = MCAttrForString(Type); if (Attr == MCSA_Invalid) return Error(TypeLoc, "unsupported attribute in '.type' directive"); if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.type' directive"); Lex(); getStreamer().EmitSymbolAttribute(Sym, Attr); return false; } /// ParseDirectiveIdent /// ::= .ident string bool ELFAsmParser::ParseDirectiveIdent(StringRef, SMLoc) { if (getLexer().isNot(AsmToken::String)) return TokError("unexpected token in '.ident' directive"); StringRef Data = getTok().getIdentifier(); Lex(); if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.ident' directive"); Lex(); getStreamer().EmitIdent(Data); return false; } /// ParseDirectiveSymver /// ::= .symver foo, bar2@zed bool ELFAsmParser::ParseDirectiveSymver(StringRef, SMLoc) { StringRef Name; if (getParser().parseIdentifier(Name)) return TokError("expected identifier in directive"); if (getLexer().isNot(AsmToken::Comma)) return TokError("expected a comma"); // ARM assembly uses @ for a comment... // except when parsing the second parameter of the .symver directive. // Force the next symbol to allow @ in the identifier, which is // required for this directive and then reset it to its initial state. const bool AllowAtInIdentifier = getLexer().getAllowAtInIdentifier(); getLexer().setAllowAtInIdentifier(true); Lex(); getLexer().setAllowAtInIdentifier(AllowAtInIdentifier); StringRef AliasName; if (getParser().parseIdentifier(AliasName)) return TokError("expected identifier in directive"); if (AliasName.find('@') == StringRef::npos) return TokError("expected a '@' in the name"); - MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName); MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - const MCExpr *Value = MCSymbolRefExpr::create(Sym, getContext()); - - getStreamer().EmitAssignment(Alias, Value); - getStreamer().emitELFSymverDirective(Alias, Sym); + getStreamer().emitELFSymverDirective(AliasName, Sym); return false; } /// ParseDirectiveVersion /// ::= .version string bool ELFAsmParser::ParseDirectiveVersion(StringRef, SMLoc) { if (getLexer().isNot(AsmToken::String)) return TokError("unexpected token in '.version' directive"); StringRef Data = getTok().getIdentifier(); Lex(); MCSection *Note = getContext().getELFSection(".note", ELF::SHT_NOTE, 0); getStreamer().PushSection(); getStreamer().SwitchSection(Note); getStreamer().EmitIntValue(Data.size()+1, 4); // namesz. getStreamer().EmitIntValue(0, 4); // descsz = 0 (no description). getStreamer().EmitIntValue(1, 4); // type = NT_VERSION. getStreamer().EmitBytes(Data); // name. getStreamer().EmitIntValue(0, 1); // terminate the string. getStreamer().EmitValueToAlignment(4); // ensure 4 byte alignment. getStreamer().PopSection(); return false; } /// ParseDirectiveWeakref /// ::= .weakref foo, bar bool ELFAsmParser::ParseDirectiveWeakref(StringRef, SMLoc) { // FIXME: Share code with the other alias building directives. StringRef AliasName; if (getParser().parseIdentifier(AliasName)) return TokError("expected identifier in directive"); if (getLexer().isNot(AsmToken::Comma)) return TokError("expected a comma"); Lex(); StringRef Name; if (getParser().parseIdentifier(Name)) return TokError("expected identifier in directive"); MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName); MCSymbol *Sym = getContext().getOrCreateSymbol(Name); getStreamer().EmitWeakReference(Alias, Sym); return false; } bool ELFAsmParser::ParseDirectiveSubsection(StringRef, SMLoc) { const MCExpr *Subsection = nullptr; if (getLexer().isNot(AsmToken::EndOfStatement)) { if (getParser().parseExpression(Subsection)) return true; } if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in directive"); Lex(); getStreamer().SubSection(Subsection); return false; } namespace llvm { MCAsmParserExtension *createELFAsmParser() { return new ELFAsmParser; } } // end namespace llvm Index: head/contrib/llvm/lib/MC/MCStreamer.cpp =================================================================== --- head/contrib/llvm/lib/MC/MCStreamer.cpp (revision 331365) +++ head/contrib/llvm/lib/MC/MCStreamer.cpp (revision 331366) @@ -1,1011 +1,1011 @@ //===- lib/MC/MCStreamer.cpp - Streaming Machine Code Output --------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/MC/MCStreamer.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCWin64EH.h" #include "llvm/MC/MCWinEH.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include using namespace llvm; MCTargetStreamer::MCTargetStreamer(MCStreamer &S) : Streamer(S) { S.setTargetStreamer(this); } // Pin the vtables to this file. MCTargetStreamer::~MCTargetStreamer() = default; void MCTargetStreamer::emitLabel(MCSymbol *Symbol) {} void MCTargetStreamer::finish() {} void MCTargetStreamer::changeSection(const MCSection *CurSection, MCSection *Section, const MCExpr *Subsection, raw_ostream &OS) { Section->PrintSwitchToSection( *Streamer.getContext().getAsmInfo(), Streamer.getContext().getObjectFileInfo()->getTargetTriple(), OS, Subsection); } void MCTargetStreamer::emitDwarfFileDirective(StringRef Directive) { Streamer.EmitRawText(Directive); } void MCTargetStreamer::emitValue(const MCExpr *Value) { SmallString<128> Str; raw_svector_ostream OS(Str); Value->print(OS, Streamer.getContext().getAsmInfo()); Streamer.EmitRawText(OS.str()); } void MCTargetStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {} MCStreamer::MCStreamer(MCContext &Ctx) : Context(Ctx), CurrentWinFrameInfo(nullptr) { SectionStack.push_back(std::pair()); } MCStreamer::~MCStreamer() {} void MCStreamer::reset() { DwarfFrameInfos.clear(); CurrentWinFrameInfo = nullptr; WinFrameInfos.clear(); SymbolOrdering.clear(); SectionStack.clear(); SectionStack.push_back(std::pair()); } raw_ostream &MCStreamer::GetCommentOS() { // By default, discard comments. return nulls(); } void MCStreamer::emitRawComment(const Twine &T, bool TabPrefix) {} void MCStreamer::addExplicitComment(const Twine &T) {} void MCStreamer::emitExplicitComments() {} void MCStreamer::generateCompactUnwindEncodings(MCAsmBackend *MAB) { for (auto &FI : DwarfFrameInfos) FI.CompactUnwindEncoding = (MAB ? MAB->generateCompactUnwindEncoding(FI.Instructions) : 0); } /// EmitIntValue - Special case of EmitValue that avoids the client having to /// pass in a MCExpr for constant integers. void MCStreamer::EmitIntValue(uint64_t Value, unsigned Size) { assert(1 <= Size && Size <= 8 && "Invalid size"); assert((isUIntN(8 * Size, Value) || isIntN(8 * Size, Value)) && "Invalid size"); char buf[8]; const bool isLittleEndian = Context.getAsmInfo()->isLittleEndian(); for (unsigned i = 0; i != Size; ++i) { unsigned index = isLittleEndian ? i : (Size - i - 1); buf[i] = uint8_t(Value >> (index * 8)); } EmitBytes(StringRef(buf, Size)); } /// EmitULEB128Value - Special case of EmitULEB128Value that avoids the /// client having to pass in a MCExpr for constant integers. void MCStreamer::EmitPaddedULEB128IntValue(uint64_t Value, unsigned PadTo) { SmallString<128> Tmp; raw_svector_ostream OSE(Tmp); 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) { SmallString<128> Tmp; raw_svector_ostream OSE(Tmp); encodeSLEB128(Value, OSE); EmitBytes(OSE.str()); } void MCStreamer::EmitValue(const MCExpr *Value, unsigned Size, SMLoc Loc) { EmitValueImpl(Value, Size, Loc); } void MCStreamer::EmitSymbolValue(const MCSymbol *Sym, unsigned Size, bool IsSectionRelative) { assert((!IsSectionRelative || Size == 4) && "SectionRelative value requires 4-bytes"); if (!IsSectionRelative) EmitValueImpl(MCSymbolRefExpr::create(Sym, getContext()), Size); else EmitCOFFSecRel32(Sym, /*Offset=*/0); } void MCStreamer::EmitDTPRel64Value(const MCExpr *Value) { report_fatal_error("unsupported directive in streamer"); } void MCStreamer::EmitDTPRel32Value(const MCExpr *Value) { report_fatal_error("unsupported directive in streamer"); } void MCStreamer::EmitTPRel64Value(const MCExpr *Value) { report_fatal_error("unsupported directive in streamer"); } void MCStreamer::EmitTPRel32Value(const MCExpr *Value) { report_fatal_error("unsupported directive in streamer"); } void MCStreamer::EmitGPRel64Value(const MCExpr *Value) { report_fatal_error("unsupported directive in streamer"); } void MCStreamer::EmitGPRel32Value(const MCExpr *Value) { report_fatal_error("unsupported directive in streamer"); } /// Emit NumBytes bytes worth of the value specified by FillValue. /// This implements directives such as '.space'. void MCStreamer::emitFill(uint64_t NumBytes, uint8_t FillValue) { emitFill(*MCConstantExpr::create(NumBytes, getContext()), FillValue); } void MCStreamer::emitFill(uint64_t NumValues, int64_t Size, int64_t Expr) { int64_t NonZeroSize = Size > 4 ? 4 : Size; Expr &= ~0ULL >> (64 - NonZeroSize * 8); for (uint64_t i = 0, e = NumValues; i != e; ++i) { EmitIntValue(Expr, NonZeroSize); if (NonZeroSize < Size) EmitIntValue(0, Size - NonZeroSize); } } /// The implementation in this class just redirects to emitFill. void MCStreamer::EmitZeros(uint64_t NumBytes) { emitFill(NumBytes, 0); } unsigned MCStreamer::EmitDwarfFileDirective(unsigned FileNo, StringRef Directory, StringRef Filename, unsigned CUID) { return getContext().getDwarfFile(Directory, Filename, FileNo, CUID); } void MCStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column, unsigned Flags, unsigned Isa, unsigned Discriminator, StringRef FileName) { getContext().setCurrentDwarfLoc(FileNo, Line, Column, Flags, Isa, Discriminator); } MCSymbol *MCStreamer::getDwarfLineTableSymbol(unsigned CUID) { MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID); if (!Table.getLabel()) { StringRef Prefix = Context.getAsmInfo()->getPrivateGlobalPrefix(); Table.setLabel( Context.getOrCreateSymbol(Prefix + "line_table_start" + Twine(CUID))); } return Table.getLabel(); } bool MCStreamer::hasUnfinishedDwarfFrameInfo() { return !DwarfFrameInfos.empty() && !DwarfFrameInfos.back().End; } 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, ArrayRef Checksum, unsigned ChecksumKind) { return getContext().getCVContext().addFile(*this, FileNo, Filename, Checksum, ChecksumKind); } bool MCStreamer::EmitCVFuncIdDirective(unsigned FunctionId) { return getContext().getCVContext().recordFunctionId(FunctionId); } bool MCStreamer::EmitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc, unsigned IAFile, unsigned IALine, unsigned IACol, SMLoc Loc) { if (getContext().getCVContext().getCVFunctionInfo(IAFunc) == nullptr) { getContext().reportError(Loc, "parent function id not introduced by " ".cv_func_id or .cv_inline_site_id"); return true; } return getContext().getCVContext().recordInlinedCallSiteId( FunctionId, IAFunc, IAFile, IALine, IACol); } void MCStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt, StringRef FileName, SMLoc Loc) { CodeViewContext &CVC = getContext().getCVContext(); MCCVFunctionInfo *FI = CVC.getCVFunctionInfo(FunctionId); if (!FI) return getContext().reportError( Loc, "function id not introduced by .cv_func_id or .cv_inline_site_id"); // Track the section if (FI->Section == nullptr) FI->Section = getCurrentSectionOnly(); else if (FI->Section != getCurrentSectionOnly()) return getContext().reportError( Loc, "all .cv_loc directives for a function must be in the same section"); CVC.setCurrentCVLoc(FunctionId, FileNo, Line, Column, PrologueEnd, IsStmt); } void MCStreamer::EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *Begin, const MCSymbol *End) {} void MCStreamer::EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, const MCSymbol *FnStartSym, const MCSymbol *FnEndSym) {} void MCStreamer::EmitCVDefRangeDirective( ArrayRef> Ranges, StringRef FixedSizePortion) {} void MCStreamer::EmitEHSymAttributes(const MCSymbol *Symbol, MCSymbol *EHSymbol) { } void MCStreamer::InitSections(bool NoExecStack) { SwitchSection(getContext().getObjectFileInfo()->getTextSection()); } void MCStreamer::AssignFragment(MCSymbol *Symbol, MCFragment *Fragment) { assert(Fragment); Symbol->setFragment(Fragment); // As we emit symbols into a section, track the order so that they can // be sorted upon later. Zero is reserved to mean 'unemitted'. SymbolOrdering[Symbol] = 1 + SymbolOrdering.size(); } void MCStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc) { Symbol->redefineIfPossible(); if (!Symbol->isUndefined() || Symbol->isVariable()) return getContext().reportError(Loc, "invalid symbol redefinition"); assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); assert(getCurrentSectionOnly() && "Cannot emit before setting section!"); assert(!Symbol->getFragment() && "Unexpected fragment on symbol data!"); assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); Symbol->setFragment(&getCurrentSectionOnly()->getDummyFragment()); MCTargetStreamer *TS = getTargetStreamer(); if (TS) TS->emitLabel(Symbol); } void MCStreamer::EmitCFISections(bool EH, bool Debug) { assert(EH || Debug); } void MCStreamer::EmitCFIStartProc(bool IsSimple) { if (hasUnfinishedDwarfFrameInfo()) getContext().reportError( SMLoc(), "starting new .cfi frame before finishing the previous one"); MCDwarfFrameInfo Frame; Frame.IsSimple = IsSimple; EmitCFIStartProcImpl(Frame); const MCAsmInfo* MAI = Context.getAsmInfo(); if (MAI) { for (const MCCFIInstruction& Inst : MAI->getInitialFrameState()) { if (Inst.getOperation() == MCCFIInstruction::OpDefCfa || Inst.getOperation() == MCCFIInstruction::OpDefCfaRegister) { Frame.CurrentCfaRegister = Inst.getRegister(); } } } DwarfFrameInfos.push_back(Frame); } void MCStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) { } void MCStreamer::EmitCFIEndProc() { 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; } MCSymbol *MCStreamer::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 = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createDefCfa(Label, Register, Offset); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); if (!CurFrame) return; CurFrame->Instructions.push_back(Instruction); CurFrame->CurrentCfaRegister = static_cast(Register); } void MCStreamer::EmitCFIDefCfaOffset(int64_t Offset) { 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 = 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 = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createDefCfaRegister(Label, Register); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); if (!CurFrame) return; CurFrame->Instructions.push_back(Instruction); CurFrame->CurrentCfaRegister = static_cast(Register); } void MCStreamer::EmitCFIOffset(int64_t Register, int64_t Offset) { 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 = 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) { MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); if (!CurFrame) return; CurFrame->Personality = Sym; CurFrame->PersonalityEncoding = Encoding; } void MCStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) { MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); if (!CurFrame) return; CurFrame->Lsda = Sym; CurFrame->LsdaEncoding = Encoding; } void MCStreamer::EmitCFIRememberState() { 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 = 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 = 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 = 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 = 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 = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createGnuArgsSize(Label, Size); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); if (!CurFrame) return; CurFrame->Instructions.push_back(Instruction); } void MCStreamer::EmitCFISignalFrame() { MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); if (!CurFrame) return; CurFrame->IsSignalFrame = true; } void MCStreamer::EmitCFIUndefined(int64_t Register) { 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 = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createRegister(Label, Register1, Register2); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); if (!CurFrame) return; CurFrame->Instructions.push_back(Instruction); } void MCStreamer::EmitCFIWindowSave() { MCSymbol *Label = EmitCFILabel(); MCCFIInstruction Instruction = MCCFIInstruction::createWindowSave(Label); MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); if (!CurFrame) return; CurFrame->Instructions.push_back(Instruction); } 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()) { 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, SMLoc Loc) { const MCAsmInfo *MAI = Context.getAsmInfo(); if (!MAI->usesWindowsCFI()) return getContext().reportError( Loc, ".seh_* directives are not supported on this target"); if (CurrentWinFrameInfo && !CurrentWinFrameInfo->End) getContext().reportError( Loc, "Starting a function before ending the previous one!"); MCSymbol *StartProc = EmitCFILabel(); WinFrameInfos.emplace_back( llvm::make_unique(Symbol, StartProc)); CurrentWinFrameInfo = WinFrameInfos.back().get(); CurrentWinFrameInfo->TextSection = getCurrentSectionOnly(); } 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(); CurFrame->End = Label; } void MCStreamer::EmitWinCFIStartChained(SMLoc Loc) { WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) return; MCSymbol *StartProc = EmitCFILabel(); WinFrameInfos.emplace_back(llvm::make_unique( CurFrame->Function, StartProc, CurFrame)); CurrentWinFrameInfo = WinFrameInfos.back().get(); CurrentWinFrameInfo->TextSection = getCurrentSectionOnly(); } 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(); CurFrame->End = Label; CurrentWinFrameInfo = const_cast(CurFrame->ChainedParent); } 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) getContext().reportError(Loc, "Don't know what kind of handler this is!"); if (Unwind) CurFrame->HandlesUnwind = true; if (Except) CurFrame->HandlesExceptions = true; } 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, MCSection *MainCFISec, const MCSection *TextSec) { // If this is the main .text section, use the main unwind info section. if (TextSec == Context.getObjectFileInfo()->getTextSection()) return MainCFISec; const auto *TextSecCOFF = cast(TextSec); unsigned UniqueID = TextSecCOFF->getOrAssignWinCFISectionID(NextWinCFIID); // If this section is COMDAT, this unwind section should be COMDAT associative // with its group. const MCSymbol *KeySym = nullptr; if (TextSecCOFF->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) KeySym = TextSecCOFF->getCOMDATSymbol(); return Context.getAssociativeCOFFSection(cast(MainCFISec), KeySym, UniqueID); } MCSection *MCStreamer::getAssociatedPDataSection(const MCSection *TextSec) { return getWinCFISection(getContext(), &NextWinCFIID, getContext().getObjectFileInfo()->getPDataSection(), TextSec); } MCSection *MCStreamer::getAssociatedXDataSection(const MCSection *TextSec) { return getWinCFISection(getContext(), &NextWinCFIID, getContext().getObjectFileInfo()->getXDataSection(), TextSec); } void MCStreamer::EmitSyntaxDirective() {} 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); CurFrame->Instructions.push_back(Inst); } 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) return getContext().reportError(Loc, "offset is not a multiple of 16"); if (Offset > 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); CurFrame->LastFrameInst = CurFrame->Instructions.size(); CurFrame->Instructions.push_back(Inst); } void MCStreamer::EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) { WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) return; if (Size == 0) return getContext().reportError(Loc, "stack allocation size must be non-zero"); if (Size & 7) return getContext().reportError( Loc, "stack allocation size is not a multiple of 8"); MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::Alloc(Label, Size); CurFrame->Instructions.push_back(Inst); } void MCStreamer::EmitWinCFISaveReg(unsigned Register, unsigned Offset, SMLoc Loc) { WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) return; if (Offset & 7) return getContext().reportError( Loc, "register save offset is not 8 byte aligned"); MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::SaveNonVol(Label, Register, Offset); CurFrame->Instructions.push_back(Inst); } void MCStreamer::EmitWinCFISaveXMM(unsigned Register, unsigned Offset, SMLoc Loc) { WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) return; if (Offset & 0x0F) return getContext().reportError(Loc, "offset is not a multiple of 16"); MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::SaveXMM(Label, Register, Offset); CurFrame->Instructions.push_back(Inst); } 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); CurFrame->Instructions.push_back(Inst); } void MCStreamer::EmitWinCFIEndProlog(SMLoc Loc) { WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) return; MCSymbol *Label = EmitCFILabel(); CurFrame->PrologEnd = Label; } void MCStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) { } void MCStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) { } void MCStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) {} /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. void MCStreamer::EmitRawTextImpl(StringRef String) { errs() << "EmitRawText called on an MCStreamer that doesn't support it, " " something must not be fully mc'ized\n"; abort(); } void MCStreamer::EmitRawText(const Twine &T) { SmallString<128> Str; EmitRawTextImpl(T.toStringRef(Str)); } void MCStreamer::EmitWindowsUnwindTables() { } void MCStreamer::Finish() { if (!DwarfFrameInfos.empty() && !DwarfFrameInfos.back().End) getContext().reportError(SMLoc(), "Unfinished frame!"); if (!WinFrameInfos.empty() && !WinFrameInfos.back()->End) getContext().reportError(SMLoc(), "Unfinished frame!"); MCTargetStreamer *TS = getTargetStreamer(); if (TS) TS->finish(); FinishImpl(); } void MCStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { visitUsedExpr(*Value); Symbol->setVariableValue(Value); MCTargetStreamer *TS = getTargetStreamer(); if (TS) TS->emitAssignment(Symbol, Value); } void MCTargetStreamer::prettyPrintAsm(MCInstPrinter &InstPrinter, raw_ostream &OS, const MCInst &Inst, const MCSubtargetInfo &STI) { InstPrinter.printInst(&Inst, OS, "", STI); } void MCStreamer::visitUsedSymbol(const MCSymbol &Sym) { } void MCStreamer::visitUsedExpr(const MCExpr &Expr) { switch (Expr.getKind()) { case MCExpr::Target: cast(Expr).visitUsedExpr(*this); break; case MCExpr::Constant: break; case MCExpr::Binary: { const MCBinaryExpr &BE = cast(Expr); visitUsedExpr(*BE.getLHS()); visitUsedExpr(*BE.getRHS()); break; } case MCExpr::SymbolRef: visitUsedSymbol(cast(Expr).getSymbol()); break; case MCExpr::Unary: visitUsedExpr(*cast(Expr).getSubExpr()); break; } } void MCStreamer::EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, bool) { // Scan for values. for (unsigned i = Inst.getNumOperands(); i--;) if (Inst.getOperand(i).isExpr()) visitUsedExpr(*Inst.getOperand(i).getExpr()); } void MCStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) { // Get the Hi-Lo expression. const MCExpr *Diff = MCBinaryExpr::createSub(MCSymbolRefExpr::create(Hi, Context), MCSymbolRefExpr::create(Lo, Context), Context); const MCAsmInfo *MAI = Context.getAsmInfo(); if (!MAI->doesSetDirectiveSuppressReloc()) { EmitValue(Diff, Size); return; } // Otherwise, emit with .set (aka assignment). MCSymbol *SetLabel = Context.createTempSymbol("set", true); EmitAssignment(SetLabel, Diff); EmitSymbolValue(SetLabel, Size); } void MCStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {} void MCStreamer::EmitThumbFunc(MCSymbol *Func) {} void MCStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {} void MCStreamer::BeginCOFFSymbolDef(const MCSymbol *Symbol) { llvm_unreachable("this directive only supported on COFF targets"); } void MCStreamer::EndCOFFSymbolDef() { llvm_unreachable("this directive only supported on COFF targets"); } void MCStreamer::EmitFileDirective(StringRef Filename) {} void MCStreamer::EmitCOFFSymbolStorageClass(int StorageClass) { llvm_unreachable("this directive only supported on COFF targets"); } void MCStreamer::EmitCOFFSymbolType(int Type) { llvm_unreachable("this directive only supported on COFF targets"); } void MCStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} -void MCStreamer::emitELFSymverDirective(MCSymbol *Alias, +void MCStreamer::emitELFSymverDirective(StringRef AliasName, const MCSymbol *Aliasee) {} void MCStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) {} void MCStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) {} void MCStreamer::ChangeSection(MCSection *, const MCExpr *) {} void MCStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {} void MCStreamer::EmitBytes(StringRef Data) {} void MCStreamer::EmitBinaryData(StringRef Data) { EmitBytes(Data); } void MCStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) { visitUsedExpr(*Value); } void MCStreamer::EmitULEB128Value(const MCExpr *Value) {} void MCStreamer::EmitSLEB128Value(const MCExpr *Value) {} void MCStreamer::emitFill(const MCExpr &NumBytes, uint64_t Value, SMLoc Loc) {} void MCStreamer::emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, SMLoc Loc) {} void MCStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) {} void MCStreamer::EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit) {} void MCStreamer::emitValueToOffset(const MCExpr *Offset, unsigned char Value, SMLoc Loc) {} void MCStreamer::EmitBundleAlignMode(unsigned AlignPow2) {} void MCStreamer::EmitBundleLock(bool AlignToEnd) {} void MCStreamer::FinishImpl() {} void MCStreamer::EmitBundleUnlock() {} void MCStreamer::SwitchSection(MCSection *Section, const MCExpr *Subsection) { assert(Section && "Cannot switch to a null section!"); MCSectionSubPair curSection = SectionStack.back().first; SectionStack.back().second = curSection; if (MCSectionSubPair(Section, Subsection) != curSection) { ChangeSection(Section, Subsection); SectionStack.back().first = MCSectionSubPair(Section, Subsection); assert(!Section->hasEnded() && "Section already ended"); MCSymbol *Sym = Section->getBeginSymbol(); if (Sym && !Sym->isInSection()) EmitLabel(Sym); } } MCSymbol *MCStreamer::endSection(MCSection *Section) { // TODO: keep track of the last subsection so that this symbol appears in the // correct place. MCSymbol *Sym = Section->getEndSymbol(Context); if (Sym->isInSection()) return Sym; SwitchSection(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); } Index: head/contrib/llvm/lib/Object/ModuleSymbolTable.cpp =================================================================== --- head/contrib/llvm/lib/Object/ModuleSymbolTable.cpp (revision 331365) +++ head/contrib/llvm/lib/Object/ModuleSymbolTable.cpp (revision 331366) @@ -1,280 +1,204 @@ //===- ModuleSymbolTable.cpp - symbol table for in-memory IR --------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This class represents a symbol table built from in-memory IR. It provides // access to GlobalValues and should only be used if such access is required // (e.g. in the LTO implementation). // //===----------------------------------------------------------------------===// #include "llvm/Object/ModuleSymbolTable.h" #include "RecordStreamer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/Object/SymbolicFile.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include using namespace llvm; using namespace object; void ModuleSymbolTable::addModule(Module *M) { if (FirstMod) assert(FirstMod->getTargetTriple() == M->getTargetTriple()); else FirstMod = M; for (GlobalValue &GV : M->global_values()) SymTab.push_back(&GV); CollectAsmSymbols(*M, [this](StringRef Name, BasicSymbolRef::Flags Flags) { SymTab.push_back(new (AsmSymbols.Allocate()) AsmSymbol(Name, Flags)); }); } -// Ensure ELF .symver aliases get the same binding as the defined symbol -// they alias with. -static void handleSymverAliases(const Module &M, RecordStreamer &Streamer) { - if (Streamer.symverAliases().empty()) - return; - - // The name in the assembler will be mangled, but the name in the IR - // might not, so we first compute a mapping from mangled name to GV. - Mangler Mang; - SmallString<64> MangledName; - StringMap MangledNameMap; - auto GetMangledName = [&](const GlobalValue &GV) { - if (!GV.hasName()) - return; - - MangledName.clear(); - MangledName.reserve(GV.getName().size() + 1); - Mang.getNameWithPrefix(MangledName, &GV, /*CannotUsePrivateLabel=*/false); - MangledNameMap[MangledName] = &GV; - }; - for (const Function &F : M) - GetMangledName(F); - for (const GlobalVariable &GV : M.globals()) - GetMangledName(GV); - for (const GlobalAlias &GA : M.aliases()) - GetMangledName(GA); - - // Walk all the recorded .symver aliases, and set up the binding - // for each alias. - for (auto &Symver : Streamer.symverAliases()) { - const MCSymbol *Aliasee = Symver.first; - MCSymbolAttr Attr = MCSA_Invalid; - - // First check if the aliasee binding was recorded in the asm. - RecordStreamer::State state = Streamer.getSymbolState(Aliasee); - switch (state) { - case RecordStreamer::Global: - case RecordStreamer::DefinedGlobal: - Attr = MCSA_Global; - break; - case RecordStreamer::UndefinedWeak: - case RecordStreamer::DefinedWeak: - Attr = MCSA_Weak; - break; - default: - break; - } - - // If we don't have a symbol attribute from assembly, then check if - // the aliasee was defined in the IR. - if (Attr == MCSA_Invalid) { - const auto *GV = M.getNamedValue(Aliasee->getName()); - if (!GV) { - auto MI = MangledNameMap.find(Aliasee->getName()); - if (MI != MangledNameMap.end()) - GV = MI->second; - else - continue; - } - if (GV->hasExternalLinkage()) - Attr = MCSA_Global; - else if (GV->hasLocalLinkage()) - Attr = MCSA_Local; - else if (GV->isWeakForLinker()) - Attr = MCSA_Weak; - } - if (Attr == MCSA_Invalid) - continue; - - // Set the detected binding on each alias with this aliasee. - for (auto &Alias : Symver.second) - Streamer.EmitSymbolAttribute(Alias, Attr); - } -} - void ModuleSymbolTable::CollectAsmSymbols( const Module &M, function_ref AsmSymbol) { StringRef InlineAsm = M.getModuleInlineAsm(); if (InlineAsm.empty()) return; std::string Err; const Triple TT(M.getTargetTriple()); const Target *T = TargetRegistry::lookupTarget(TT.str(), Err); assert(T && T->hasMCAsmParser()); std::unique_ptr MRI(T->createMCRegInfo(TT.str())); if (!MRI) return; std::unique_ptr MAI(T->createMCAsmInfo(*MRI, TT.str())); if (!MAI) return; std::unique_ptr STI( T->createMCSubtargetInfo(TT.str(), "", "")); if (!STI) return; std::unique_ptr MCII(T->createMCInstrInfo()); if (!MCII) return; MCObjectFileInfo MOFI; MCContext MCCtx(MAI.get(), MRI.get(), &MOFI); MOFI.InitMCObjectFileInfo(TT, /*PIC*/ false, MCCtx); - RecordStreamer Streamer(MCCtx); + RecordStreamer Streamer(MCCtx, M); T->createNullTargetStreamer(Streamer); std::unique_ptr Buffer(MemoryBuffer::getMemBuffer(InlineAsm)); SourceMgr SrcMgr; SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc()); std::unique_ptr Parser( createMCAsmParser(SrcMgr, MCCtx, Streamer, *MAI)); MCTargetOptions MCOptions; std::unique_ptr TAP( T->createMCAsmParser(*STI, *Parser, *MCII, MCOptions)); if (!TAP) return; Parser->setTargetParser(*TAP); if (Parser->Run(false)) return; - handleSymverAliases(M, Streamer); + Streamer.flushSymverDirectives(); for (auto &KV : Streamer) { StringRef Key = KV.first(); RecordStreamer::State Value = KV.second; // FIXME: For now we just assume that all asm symbols are executable. uint32_t Res = BasicSymbolRef::SF_Executable; switch (Value) { case RecordStreamer::NeverSeen: llvm_unreachable("NeverSeen should have been replaced earlier"); case RecordStreamer::DefinedGlobal: Res |= BasicSymbolRef::SF_Global; break; case RecordStreamer::Defined: break; case RecordStreamer::Global: case RecordStreamer::Used: Res |= BasicSymbolRef::SF_Undefined; Res |= BasicSymbolRef::SF_Global; break; case RecordStreamer::DefinedWeak: Res |= BasicSymbolRef::SF_Weak; Res |= BasicSymbolRef::SF_Global; break; case RecordStreamer::UndefinedWeak: Res |= BasicSymbolRef::SF_Weak; Res |= BasicSymbolRef::SF_Undefined; } AsmSymbol(Key, BasicSymbolRef::Flags(Res)); } } void ModuleSymbolTable::printSymbolName(raw_ostream &OS, Symbol S) const { if (S.is()) { OS << S.get()->first; return; } auto *GV = S.get(); if (GV->hasDLLImportStorageClass()) OS << "__imp_"; Mang.getNameWithPrefix(OS, GV, false); } uint32_t ModuleSymbolTable::getSymbolFlags(Symbol S) const { if (S.is()) return S.get()->second; auto *GV = S.get(); uint32_t Res = BasicSymbolRef::SF_None; if (GV->isDeclarationForLinker()) Res |= BasicSymbolRef::SF_Undefined; else if (GV->hasHiddenVisibility() && !GV->hasLocalLinkage()) Res |= BasicSymbolRef::SF_Hidden; if (const GlobalVariable *GVar = dyn_cast(GV)) { if (GVar->isConstant()) Res |= BasicSymbolRef::SF_Const; } if (dyn_cast_or_null(GV->getBaseObject())) Res |= BasicSymbolRef::SF_Executable; if (isa(GV)) Res |= BasicSymbolRef::SF_Indirect; if (GV->hasPrivateLinkage()) Res |= BasicSymbolRef::SF_FormatSpecific; if (!GV->hasLocalLinkage()) Res |= BasicSymbolRef::SF_Global; if (GV->hasCommonLinkage()) Res |= BasicSymbolRef::SF_Common; if (GV->hasLinkOnceLinkage() || GV->hasWeakLinkage() || GV->hasExternalWeakLinkage()) Res |= BasicSymbolRef::SF_Weak; if (GV->getName().startswith("llvm.")) Res |= BasicSymbolRef::SF_FormatSpecific; else if (auto *Var = dyn_cast(GV)) { if (Var->getSection() == "llvm.metadata") Res |= BasicSymbolRef::SF_FormatSpecific; } return Res; } Index: head/contrib/llvm/lib/Object/RecordStreamer.cpp =================================================================== --- head/contrib/llvm/lib/Object/RecordStreamer.cpp (revision 331365) +++ head/contrib/llvm/lib/Object/RecordStreamer.cpp (revision 331366) @@ -1,118 +1,224 @@ //===-- RecordStreamer.cpp - Record asm defined and used symbols ----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "RecordStreamer.h" +#include "llvm/IR/Mangler.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCSymbol.h" using namespace llvm; void RecordStreamer::markDefined(const MCSymbol &Symbol) { State &S = Symbols[Symbol.getName()]; switch (S) { case DefinedGlobal: case Global: S = DefinedGlobal; break; case NeverSeen: case Defined: case Used: S = Defined; break; case DefinedWeak: break; case UndefinedWeak: S = DefinedWeak; } } void RecordStreamer::markGlobal(const MCSymbol &Symbol, MCSymbolAttr Attribute) { State &S = Symbols[Symbol.getName()]; switch (S) { case DefinedGlobal: case Defined: S = (Attribute == MCSA_Weak) ? DefinedWeak : DefinedGlobal; break; case NeverSeen: case Global: case Used: S = (Attribute == MCSA_Weak) ? UndefinedWeak : Global; break; case UndefinedWeak: case DefinedWeak: break; } } void RecordStreamer::markUsed(const MCSymbol &Symbol) { State &S = Symbols[Symbol.getName()]; switch (S) { case DefinedGlobal: case Defined: case Global: case DefinedWeak: case UndefinedWeak: break; case NeverSeen: case Used: S = Used; break; } } void RecordStreamer::visitUsedSymbol(const MCSymbol &Sym) { markUsed(Sym); } -RecordStreamer::RecordStreamer(MCContext &Context) : MCStreamer(Context) {} +RecordStreamer::RecordStreamer(MCContext &Context, const Module &M) + : MCStreamer(Context), M(M) {} RecordStreamer::const_iterator RecordStreamer::begin() { return Symbols.begin(); } RecordStreamer::const_iterator RecordStreamer::end() { return Symbols.end(); } void RecordStreamer::EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, bool) { MCStreamer::EmitInstruction(Inst, STI); } void RecordStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc) { MCStreamer::EmitLabel(Symbol); markDefined(*Symbol); } void RecordStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { markDefined(*Symbol); MCStreamer::EmitAssignment(Symbol, Value); } bool RecordStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { if (Attribute == MCSA_Global || Attribute == MCSA_Weak) markGlobal(*Symbol, Attribute); if (Attribute == MCSA_LazyReference) markUsed(*Symbol); return true; } void RecordStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { markDefined(*Symbol); } void RecordStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { markDefined(*Symbol); } -void RecordStreamer::emitELFSymverDirective(MCSymbol *Alias, +RecordStreamer::State RecordStreamer::getSymbolState(const MCSymbol *Sym) { + auto SI = Symbols.find(Sym->getName()); + if (SI == Symbols.end()) + return NeverSeen; + return SI->second; +} + +void RecordStreamer::emitELFSymverDirective(StringRef AliasName, const MCSymbol *Aliasee) { - SymverAliasMap[Aliasee].push_back(Alias); + SymverAliasMap[Aliasee].push_back(AliasName); +} + +void RecordStreamer::flushSymverDirectives() { + // Mapping from mangled name to GV. + StringMap MangledNameMap; + // The name in the assembler will be mangled, but the name in the IR + // might not, so we first compute a mapping from mangled name to GV. + Mangler Mang; + SmallString<64> MangledName; + for (const GlobalValue &GV : M.global_values()) { + if (!GV.hasName()) + continue; + MangledName.clear(); + MangledName.reserve(GV.getName().size() + 1); + Mang.getNameWithPrefix(MangledName, &GV, /*CannotUsePrivateLabel=*/false); + MangledNameMap[MangledName] = &GV; + } + + // Walk all the recorded .symver aliases, and set up the binding + // for each alias. + for (auto &Symver : SymverAliasMap) { + const MCSymbol *Aliasee = Symver.first; + MCSymbolAttr Attr = MCSA_Invalid; + bool IsDefined = false; + + // First check if the aliasee binding was recorded in the asm. + RecordStreamer::State state = getSymbolState(Aliasee); + switch (state) { + case RecordStreamer::Global: + case RecordStreamer::DefinedGlobal: + Attr = MCSA_Global; + break; + case RecordStreamer::UndefinedWeak: + case RecordStreamer::DefinedWeak: + Attr = MCSA_Weak; + break; + default: + break; + } + + switch (state) { + case RecordStreamer::Defined: + case RecordStreamer::DefinedGlobal: + case RecordStreamer::DefinedWeak: + IsDefined = true; + break; + case RecordStreamer::NeverSeen: + case RecordStreamer::Global: + case RecordStreamer::Used: + case RecordStreamer::UndefinedWeak: + break; + } + + if (Attr == MCSA_Invalid || !IsDefined) { + const GlobalValue *GV = M.getNamedValue(Aliasee->getName()); + if (!GV) { + auto MI = MangledNameMap.find(Aliasee->getName()); + if (MI != MangledNameMap.end()) + GV = MI->second; + } + if (GV) { + // If we don't have a symbol attribute from assembly, then check if + // the aliasee was defined in the IR. + if (Attr == MCSA_Invalid) { + if (GV->hasExternalLinkage()) + Attr = MCSA_Global; + else if (GV->hasLocalLinkage()) + Attr = MCSA_Local; + else if (GV->isWeakForLinker()) + Attr = MCSA_Weak; + } + IsDefined = IsDefined || !GV->isDeclarationForLinker(); + } + } + + // Set the detected binding on each alias with this aliasee. + for (auto AliasName : Symver.second) { + std::pair Split = AliasName.split("@@@"); + SmallString<128> NewName; + if (!Split.second.empty() && !Split.second.startswith("@")) { + // Special processing for "@@@" according + // https://sourceware.org/binutils/docs/as/Symver.html + const char *Separator = IsDefined ? "@@" : "@"; + AliasName = + (Split.first + Separator + Split.second).toStringRef(NewName); + } + MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName); + // TODO: Handle "@@@". Depending on SymbolAttribute value it needs to be + // converted into @ or @@. + const MCExpr *Value = MCSymbolRefExpr::create(Aliasee, getContext()); + EmitAssignment(Alias, Value); + if (Attr != MCSA_Invalid) + EmitSymbolAttribute(Alias, Attr); + } + } } Index: head/contrib/llvm/lib/Object/RecordStreamer.h =================================================================== --- head/contrib/llvm/lib/Object/RecordStreamer.h (revision 331365) +++ head/contrib/llvm/lib/Object/RecordStreamer.h (revision 331366) @@ -1,75 +1,73 @@ //===- RecordStreamer.h - Record asm defined and used symbols ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_OBJECT_RECORDSTREAMER_H #define LLVM_LIB_OBJECT_RECORDSTREAMER_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/SMLoc.h" #include namespace llvm { +class GlobalValue; +class Module; + class RecordStreamer : public MCStreamer { public: enum State { NeverSeen, Global, Defined, DefinedGlobal, DefinedWeak, Used, UndefinedWeak}; private: + const Module &M; StringMap Symbols; // Map of aliases created by .symver directives, saved so we can update // their symbol binding after parsing complete. This maps from each // aliasee to its list of aliases. - DenseMap> SymverAliasMap; + DenseMap> SymverAliasMap; + /// Get the state recorded for the given symbol. + State getSymbolState(const MCSymbol *Sym); + void markDefined(const MCSymbol &Symbol); void markGlobal(const MCSymbol &Symbol, MCSymbolAttr Attribute); void markUsed(const MCSymbol &Symbol); void visitUsedSymbol(const MCSymbol &Sym) override; public: - RecordStreamer(MCContext &Context); + RecordStreamer(MCContext &Context, const Module &M); using const_iterator = StringMap::const_iterator; const_iterator begin(); const_iterator end(); void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, bool) override; void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override; void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; void EmitZerofill(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; /// Record .symver aliases for later processing. - void emitELFSymverDirective(MCSymbol *Alias, + void emitELFSymverDirective(StringRef AliasName, const MCSymbol *Aliasee) override; - /// Return the map of .symver aliasee to associated aliases. - DenseMap> &symverAliases() { - return SymverAliasMap; - } - - /// Get the state recorded for the given symbol. - State getSymbolState(const MCSymbol *Sym) { - auto SI = Symbols.find(Sym->getName()); - if (SI == Symbols.end()) - return NeverSeen; - return SI->second; - } + // Emit ELF .symver aliases and ensure they have the same binding as the + // defined symbol they alias with. + void flushSymverDirectives(); }; } // end namespace llvm #endif // LLVM_LIB_OBJECT_RECORDSTREAMER_H