| //===- lib/MC/ARMELFStreamer.cpp - ELF Object Output for ARM --------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file assembles .s files and emits ARM ELF .o object files. Different | |
| // from generic ELF streamer in emitting mapping symbols ($a, $t and $d) to | |
| // delimit regions of data and code. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "ARMRegisterInfo.h" | |
| #include "ARMUnwindOpAsm.h" | |
| #include "llvm/ADT/DenseMap.h" | |
| #include "llvm/ADT/SmallString.h" | |
| #include "llvm/ADT/SmallVector.h" | |
| #include "llvm/ADT/StringRef.h" | |
| #include "llvm/ADT/Triple.h" | |
| #include "llvm/ADT/Twine.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/MCELFStreamer.h" | |
| #include "llvm/MC/MCExpr.h" | |
| #include "llvm/MC/MCFixup.h" | |
| #include "llvm/MC/MCFragment.h" | |
| #include "llvm/MC/MCInst.h" | |
| #include "llvm/MC/MCInstPrinter.h" | |
| #include "llvm/MC/MCObjectWriter.h" | |
| #include "llvm/MC/MCRegisterInfo.h" | |
| #include "llvm/MC/MCSection.h" | |
| #include "llvm/MC/MCSectionELF.h" | |
| #include "llvm/MC/MCStreamer.h" | |
| #include "llvm/MC/MCSubtargetInfo.h" | |
| #include "llvm/MC/MCSymbol.h" | |
| #include "llvm/MC/MCSymbolELF.h" | |
| #include "llvm/MC/SectionKind.h" | |
| #include "llvm/Support/ARMBuildAttributes.h" | |
| #include "llvm/Support/ARMEHABI.h" | |
| #include "llvm/Support/Casting.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #include "llvm/Support/FormattedStream.h" | |
| #include "llvm/Support/LEB128.h" | |
| #include "llvm/Support/TargetParser.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| #include <algorithm> | |
| #include <cassert> | |
| #include <climits> | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <string> | |
| using namespace llvm; | |
| static std::string GetAEABIUnwindPersonalityName(unsigned Index) { | |
| assert(Index < ARM::EHABI::NUM_PERSONALITY_INDEX && | |
| "Invalid personality index"); | |
| return (Twine("__aeabi_unwind_cpp_pr") + Twine(Index)).str(); | |
| } | |
| namespace { | |
| class ARMELFStreamer; | |
| class ARMTargetAsmStreamer : public ARMTargetStreamer { | |
| formatted_raw_ostream &OS; | |
| MCInstPrinter &InstPrinter; | |
| bool IsVerboseAsm; | |
| void emitFnStart() override; | |
| void emitFnEnd() override; | |
| void emitCantUnwind() override; | |
| void emitPersonality(const MCSymbol *Personality) override; | |
| void emitPersonalityIndex(unsigned Index) override; | |
| void emitHandlerData() override; | |
| void emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset = 0) override; | |
| void emitMovSP(unsigned Reg, int64_t Offset = 0) override; | |
| void emitPad(int64_t Offset) override; | |
| void emitRegSave(const SmallVectorImpl<unsigned> &RegList, | |
| bool isVector) override; | |
| void emitUnwindRaw(int64_t Offset, | |
| const SmallVectorImpl<uint8_t> &Opcodes) override; | |
| void switchVendor(StringRef Vendor) override; | |
| void emitAttribute(unsigned Attribute, unsigned Value) override; | |
| void emitTextAttribute(unsigned Attribute, StringRef String) override; | |
| void emitIntTextAttribute(unsigned Attribute, unsigned IntValue, | |
| StringRef StringValue) override; | |
| void emitArch(ARM::ArchKind Arch) override; | |
| void emitArchExtension(unsigned ArchExt) override; | |
| void emitObjectArch(ARM::ArchKind Arch) override; | |
| void emitFPU(unsigned FPU) override; | |
| void emitInst(uint32_t Inst, char Suffix = '\0') override; | |
| void finishAttributeSection() override; | |
| void AnnotateTLSDescriptorSequence(const MCSymbolRefExpr *SRE) override; | |
| void emitThumbSet(MCSymbol *Symbol, const MCExpr *Value) override; | |
| public: | |
| ARMTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS, | |
| MCInstPrinter &InstPrinter, bool VerboseAsm); | |
| }; | |
| ARMTargetAsmStreamer::ARMTargetAsmStreamer(MCStreamer &S, | |
| formatted_raw_ostream &OS, | |
| MCInstPrinter &InstPrinter, | |
| bool VerboseAsm) | |
| : ARMTargetStreamer(S), OS(OS), InstPrinter(InstPrinter), | |
| IsVerboseAsm(VerboseAsm) {} | |
| void ARMTargetAsmStreamer::emitFnStart() { OS << "\t.fnstart\n"; } | |
| void ARMTargetAsmStreamer::emitFnEnd() { OS << "\t.fnend\n"; } | |
| void ARMTargetAsmStreamer::emitCantUnwind() { OS << "\t.cantunwind\n"; } | |
| void ARMTargetAsmStreamer::emitPersonality(const MCSymbol *Personality) { | |
| OS << "\t.personality " << Personality->getName() << '\n'; | |
| } | |
| void ARMTargetAsmStreamer::emitPersonalityIndex(unsigned Index) { | |
| OS << "\t.personalityindex " << Index << '\n'; | |
| } | |
| void ARMTargetAsmStreamer::emitHandlerData() { OS << "\t.handlerdata\n"; } | |
| void ARMTargetAsmStreamer::emitSetFP(unsigned FpReg, unsigned SpReg, | |
| int64_t Offset) { | |
| OS << "\t.setfp\t"; | |
| InstPrinter.printRegName(OS, FpReg); | |
| OS << ", "; | |
| InstPrinter.printRegName(OS, SpReg); | |
| if (Offset) | |
| OS << ", #" << Offset; | |
| OS << '\n'; | |
| } | |
| void ARMTargetAsmStreamer::emitMovSP(unsigned Reg, int64_t Offset) { | |
| assert((Reg != ARM::SP && Reg != ARM::PC) && | |
| "the operand of .movsp cannot be either sp or pc"); | |
| OS << "\t.movsp\t"; | |
| InstPrinter.printRegName(OS, Reg); | |
| if (Offset) | |
| OS << ", #" << Offset; | |
| OS << '\n'; | |
| } | |
| void ARMTargetAsmStreamer::emitPad(int64_t Offset) { | |
| OS << "\t.pad\t#" << Offset << '\n'; | |
| } | |
| void ARMTargetAsmStreamer::emitRegSave(const SmallVectorImpl<unsigned> &RegList, | |
| bool isVector) { | |
| assert(RegList.size() && "RegList should not be empty"); | |
| if (isVector) | |
| OS << "\t.vsave\t{"; | |
| else | |
| OS << "\t.save\t{"; | |
| InstPrinter.printRegName(OS, RegList[0]); | |
| for (unsigned i = 1, e = RegList.size(); i != e; ++i) { | |
| OS << ", "; | |
| InstPrinter.printRegName(OS, RegList[i]); | |
| } | |
| OS << "}\n"; | |
| } | |
| void ARMTargetAsmStreamer::switchVendor(StringRef Vendor) {} | |
| void ARMTargetAsmStreamer::emitAttribute(unsigned Attribute, unsigned Value) { | |
| OS << "\t.eabi_attribute\t" << Attribute << ", " << Twine(Value); | |
| if (IsVerboseAsm) { | |
| StringRef Name = ARMBuildAttrs::AttrTypeAsString(Attribute); | |
| if (!Name.empty()) | |
| OS << "\t@ " << Name; | |
| } | |
| OS << "\n"; | |
| } | |
| void ARMTargetAsmStreamer::emitTextAttribute(unsigned Attribute, | |
| StringRef String) { | |
| switch (Attribute) { | |
| case ARMBuildAttrs::CPU_name: | |
| OS << "\t.cpu\t" << String.lower(); | |
| break; | |
| default: | |
| OS << "\t.eabi_attribute\t" << Attribute << ", \"" << String << "\""; | |
| if (IsVerboseAsm) { | |
| StringRef Name = ARMBuildAttrs::AttrTypeAsString(Attribute); | |
| if (!Name.empty()) | |
| OS << "\t@ " << Name; | |
| } | |
| break; | |
| } | |
| OS << "\n"; | |
| } | |
| void ARMTargetAsmStreamer::emitIntTextAttribute(unsigned Attribute, | |
| unsigned IntValue, | |
| StringRef StringValue) { | |
| switch (Attribute) { | |
| default: llvm_unreachable("unsupported multi-value attribute in asm mode"); | |
| case ARMBuildAttrs::compatibility: | |
| OS << "\t.eabi_attribute\t" << Attribute << ", " << IntValue; | |
| if (!StringValue.empty()) | |
| OS << ", \"" << StringValue << "\""; | |
| if (IsVerboseAsm) | |
| OS << "\t@ " << ARMBuildAttrs::AttrTypeAsString(Attribute); | |
| break; | |
| } | |
| OS << "\n"; | |
| } | |
| void ARMTargetAsmStreamer::emitArch(ARM::ArchKind Arch) { | |
| OS << "\t.arch\t" << ARM::getArchName(Arch) << "\n"; | |
| } | |
| void ARMTargetAsmStreamer::emitArchExtension(unsigned ArchExt) { | |
| OS << "\t.arch_extension\t" << ARM::getArchExtName(ArchExt) << "\n"; | |
| } | |
| void ARMTargetAsmStreamer::emitObjectArch(ARM::ArchKind Arch) { | |
| OS << "\t.object_arch\t" << ARM::getArchName(Arch) << '\n'; | |
| } | |
| void ARMTargetAsmStreamer::emitFPU(unsigned FPU) { | |
| OS << "\t.fpu\t" << ARM::getFPUName(FPU) << "\n"; | |
| } | |
| void ARMTargetAsmStreamer::finishAttributeSection() {} | |
| void | |
| ARMTargetAsmStreamer::AnnotateTLSDescriptorSequence(const MCSymbolRefExpr *S) { | |
| OS << "\t.tlsdescseq\t" << S->getSymbol().getName(); | |
| } | |
| void ARMTargetAsmStreamer::emitThumbSet(MCSymbol *Symbol, const MCExpr *Value) { | |
| const MCAsmInfo *MAI = Streamer.getContext().getAsmInfo(); | |
| OS << "\t.thumb_set\t"; | |
| Symbol->print(OS, MAI); | |
| OS << ", "; | |
| Value->print(OS, MAI); | |
| OS << '\n'; | |
| } | |
| void ARMTargetAsmStreamer::emitInst(uint32_t Inst, char Suffix) { | |
| OS << "\t.inst"; | |
| if (Suffix) | |
| OS << "." << Suffix; | |
| OS << "\t0x" << Twine::utohexstr(Inst) << "\n"; | |
| } | |
| void ARMTargetAsmStreamer::emitUnwindRaw(int64_t Offset, | |
| const SmallVectorImpl<uint8_t> &Opcodes) { | |
| OS << "\t.unwind_raw " << Offset; | |
| for (SmallVectorImpl<uint8_t>::const_iterator OCI = Opcodes.begin(), | |
| OCE = Opcodes.end(); | |
| OCI != OCE; ++OCI) | |
| OS << ", 0x" << Twine::utohexstr(*OCI); | |
| OS << '\n'; | |
| } | |
| class ARMTargetELFStreamer : public ARMTargetStreamer { | |
| private: | |
| // This structure holds all attributes, accounting for | |
| // their string/numeric value, so we can later emit them | |
| // in declaration order, keeping all in the same vector | |
| struct AttributeItem { | |
| enum { | |
| HiddenAttribute = 0, | |
| NumericAttribute, | |
| TextAttribute, | |
| NumericAndTextAttributes | |
| } Type; | |
| unsigned Tag; | |
| unsigned IntValue; | |
| std::string StringValue; | |
| static bool LessTag(const AttributeItem &LHS, const AttributeItem &RHS) { | |
| // The conformance tag must be emitted first when serialised | |
| // into an object file. Specifically, the addenda to the ARM ABI | |
| // states that (2.3.7.4): | |
| // | |
| // "To simplify recognition by consumers in the common case of | |
| // claiming conformity for the whole file, this tag should be | |
| // emitted first in a file-scope sub-subsection of the first | |
| // public subsection of the attributes section." | |
| // | |
| // So it is special-cased in this comparison predicate when the | |
| // attributes are sorted in finishAttributeSection(). | |
| return (RHS.Tag != ARMBuildAttrs::conformance) && | |
| ((LHS.Tag == ARMBuildAttrs::conformance) || (LHS.Tag < RHS.Tag)); | |
| } | |
| }; | |
| StringRef CurrentVendor; | |
| unsigned FPU = ARM::FK_INVALID; | |
| ARM::ArchKind Arch = ARM::ArchKind::INVALID; | |
| ARM::ArchKind EmittedArch = ARM::ArchKind::INVALID; | |
| SmallVector<AttributeItem, 64> Contents; | |
| MCSection *AttributeSection = nullptr; | |
| AttributeItem *getAttributeItem(unsigned Attribute) { | |
| for (size_t i = 0; i < Contents.size(); ++i) | |
| if (Contents[i].Tag == Attribute) | |
| return &Contents[i]; | |
| return nullptr; | |
| } | |
| void setAttributeItem(unsigned Attribute, unsigned Value, | |
| bool OverwriteExisting) { | |
| // Look for existing attribute item | |
| if (AttributeItem *Item = getAttributeItem(Attribute)) { | |
| if (!OverwriteExisting) | |
| return; | |
| Item->Type = AttributeItem::NumericAttribute; | |
| Item->IntValue = Value; | |
| return; | |
| } | |
| // Create new attribute item | |
| AttributeItem Item = { | |
| AttributeItem::NumericAttribute, | |
| Attribute, | |
| Value, | |
| StringRef("") | |
| }; | |
| Contents.push_back(Item); | |
| } | |
| void setAttributeItem(unsigned Attribute, StringRef Value, | |
| bool OverwriteExisting) { | |
| // Look for existing attribute item | |
| if (AttributeItem *Item = getAttributeItem(Attribute)) { | |
| if (!OverwriteExisting) | |
| return; | |
| Item->Type = AttributeItem::TextAttribute; | |
| Item->StringValue = Value; | |
| return; | |
| } | |
| // Create new attribute item | |
| AttributeItem Item = { | |
| AttributeItem::TextAttribute, | |
| Attribute, | |
| 0, | |
| Value | |
| }; | |
| Contents.push_back(Item); | |
| } | |
| void setAttributeItems(unsigned Attribute, unsigned IntValue, | |
| StringRef StringValue, bool OverwriteExisting) { | |
| // Look for existing attribute item | |
| if (AttributeItem *Item = getAttributeItem(Attribute)) { | |
| if (!OverwriteExisting) | |
| return; | |
| Item->Type = AttributeItem::NumericAndTextAttributes; | |
| Item->IntValue = IntValue; | |
| Item->StringValue = StringValue; | |
| return; | |
| } | |
| // Create new attribute item | |
| AttributeItem Item = { | |
| AttributeItem::NumericAndTextAttributes, | |
| Attribute, | |
| IntValue, | |
| StringValue | |
| }; | |
| Contents.push_back(Item); | |
| } | |
| void emitArchDefaultAttributes(); | |
| void emitFPUDefaultAttributes(); | |
| ARMELFStreamer &getStreamer(); | |
| void emitFnStart() override; | |
| void emitFnEnd() override; | |
| void emitCantUnwind() override; | |
| void emitPersonality(const MCSymbol *Personality) override; | |
| void emitPersonalityIndex(unsigned Index) override; | |
| void emitHandlerData() override; | |
| void emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset = 0) override; | |
| void emitMovSP(unsigned Reg, int64_t Offset = 0) override; | |
| void emitPad(int64_t Offset) override; | |
| void emitRegSave(const SmallVectorImpl<unsigned> &RegList, | |
| bool isVector) override; | |
| void emitUnwindRaw(int64_t Offset, | |
| const SmallVectorImpl<uint8_t> &Opcodes) override; | |
| void switchVendor(StringRef Vendor) override; | |
| void emitAttribute(unsigned Attribute, unsigned Value) override; | |
| void emitTextAttribute(unsigned Attribute, StringRef String) override; | |
| void emitIntTextAttribute(unsigned Attribute, unsigned IntValue, | |
| StringRef StringValue) override; | |
| void emitArch(ARM::ArchKind Arch) override; | |
| void emitObjectArch(ARM::ArchKind Arch) override; | |
| void emitFPU(unsigned FPU) override; | |
| void emitInst(uint32_t Inst, char Suffix = '\0') override; | |
| void finishAttributeSection() override; | |
| void emitLabel(MCSymbol *Symbol) override; | |
| void AnnotateTLSDescriptorSequence(const MCSymbolRefExpr *SRE) override; | |
| void emitThumbSet(MCSymbol *Symbol, const MCExpr *Value) override; | |
| size_t calculateContentSize() const; | |
| // Reset state between object emissions | |
| void reset() override; | |
| public: | |
| ARMTargetELFStreamer(MCStreamer &S) | |
| : ARMTargetStreamer(S), CurrentVendor("aeabi") {} | |
| }; | |
| /// Extend the generic ELFStreamer class so that it can emit mapping symbols at | |
| /// the appropriate points in the object files. These symbols are defined in the | |
| /// ARM ELF ABI: infocenter.arm.com/help/topic/com.arm.../IHI0044D_aaelf.pdf. | |
| /// | |
| /// In brief: $a, $t or $d should be emitted at the start of each contiguous | |
| /// region of ARM code, Thumb code or data in a section. In practice, this | |
| /// emission does not rely on explicit assembler directives but on inherent | |
| /// properties of the directives doing the emission (e.g. ".byte" is data, "add | |
| /// r0, r0, r0" an instruction). | |
| /// | |
| /// As a result this system is orthogonal to the DataRegion infrastructure used | |
| /// by MachO. Beware! | |
| class ARMELFStreamer : public MCELFStreamer { | |
| public: | |
| friend class ARMTargetELFStreamer; | |
| ARMELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB, | |
| std::unique_ptr<MCObjectWriter> OW, | |
| std::unique_ptr<MCCodeEmitter> Emitter, bool IsThumb, | |
| bool IsAndroid) | |
| : MCELFStreamer(Context, std::move(TAB), std::move(OW), | |
| std::move(Emitter)), | |
| IsThumb(IsThumb), IsAndroid(IsAndroid) { | |
| EHReset(); | |
| } | |
| ~ARMELFStreamer() override = default; | |
| void FinishImpl() override; | |
| // ARM exception handling directives | |
| void emitFnStart(); | |
| void emitFnEnd(); | |
| void emitCantUnwind(); | |
| void emitPersonality(const MCSymbol *Per); | |
| void emitPersonalityIndex(unsigned index); | |
| void emitHandlerData(); | |
| void emitSetFP(unsigned NewFpReg, unsigned NewSpReg, int64_t Offset = 0); | |
| void emitMovSP(unsigned Reg, int64_t Offset = 0); | |
| void emitPad(int64_t Offset); | |
| void emitRegSave(const SmallVectorImpl<unsigned> &RegList, bool isVector); | |
| void emitUnwindRaw(int64_t Offset, const SmallVectorImpl<uint8_t> &Opcodes); | |
| void emitFill(const MCExpr &NumBytes, uint64_t FillValue, | |
| SMLoc Loc) override { | |
| EmitDataMappingSymbol(); | |
| MCObjectStreamer::emitFill(NumBytes, FillValue, Loc); | |
| } | |
| void ChangeSection(MCSection *Section, const MCExpr *Subsection) override { | |
| LastMappingSymbols[getCurrentSection().first] = std::move(LastEMSInfo); | |
| MCELFStreamer::ChangeSection(Section, Subsection); | |
| auto LastMappingSymbol = LastMappingSymbols.find(Section); | |
| if (LastMappingSymbol != LastMappingSymbols.end()) { | |
| LastEMSInfo = std::move(LastMappingSymbol->second); | |
| return; | |
| } | |
| LastEMSInfo.reset(new ElfMappingSymbolInfo(SMLoc(), nullptr, 0)); | |
| } | |
| /// This function is the one used to emit instruction data into the ELF | |
| /// streamer. We override it to add the appropriate mapping symbol if | |
| /// necessary. | |
| void EmitInstruction(const MCInst &Inst, | |
| const MCSubtargetInfo &STI) override { | |
| if (IsThumb) | |
| EmitThumbMappingSymbol(); | |
| else | |
| EmitARMMappingSymbol(); | |
| MCELFStreamer::EmitInstruction(Inst, STI); | |
| } | |
| void emitInst(uint32_t Inst, char Suffix) { | |
| unsigned Size; | |
| char Buffer[4]; | |
| const bool LittleEndian = getContext().getAsmInfo()->isLittleEndian(); | |
| switch (Suffix) { | |
| case '\0': | |
| Size = 4; | |
| assert(!IsThumb); | |
| EmitARMMappingSymbol(); | |
| for (unsigned II = 0, IE = Size; II != IE; II++) { | |
| const unsigned I = LittleEndian ? (Size - II - 1) : II; | |
| Buffer[Size - II - 1] = uint8_t(Inst >> I * CHAR_BIT); | |
| } | |
| break; | |
| case 'n': | |
| case 'w': | |
| Size = (Suffix == 'n' ? 2 : 4); | |
| assert(IsThumb); | |
| EmitThumbMappingSymbol(); | |
| // Thumb wide instructions are emitted as a pair of 16-bit words of the | |
| // appropriate endianness. | |
| for (unsigned II = 0, IE = Size; II != IE; II = II + 2) { | |
| const unsigned I0 = LittleEndian ? II + 0 : II + 1; | |
| const unsigned I1 = LittleEndian ? II + 1 : II + 0; | |
| Buffer[Size - II - 2] = uint8_t(Inst >> I0 * CHAR_BIT); | |
| Buffer[Size - II - 1] = uint8_t(Inst >> I1 * CHAR_BIT); | |
| } | |
| break; | |
| default: | |
| llvm_unreachable("Invalid Suffix"); | |
| } | |
| MCELFStreamer::EmitBytes(StringRef(Buffer, Size)); | |
| } | |
| /// This is one of the functions used to emit data into an ELF section, so the | |
| /// ARM streamer overrides it to add the appropriate mapping symbol ($d) if | |
| /// necessary. | |
| void EmitBytes(StringRef Data) override { | |
| EmitDataMappingSymbol(); | |
| MCELFStreamer::EmitBytes(Data); | |
| } | |
| void FlushPendingMappingSymbol() { | |
| if (!LastEMSInfo->hasInfo()) | |
| return; | |
| ElfMappingSymbolInfo *EMS = LastEMSInfo.get(); | |
| EmitMappingSymbol("$d", EMS->Loc, EMS->F, EMS->Offset); | |
| EMS->resetInfo(); | |
| } | |
| /// This is one of the functions used to emit data into an ELF section, so the | |
| /// ARM streamer overrides it to add the appropriate mapping symbol ($d) if | |
| /// necessary. | |
| void EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) override { | |
| if (const MCSymbolRefExpr *SRE = dyn_cast_or_null<MCSymbolRefExpr>(Value)) { | |
| if (SRE->getKind() == MCSymbolRefExpr::VK_ARM_SBREL && !(Size == 4)) { | |
| getContext().reportError(Loc, "relocated expression must be 32-bit"); | |
| return; | |
| } | |
| getOrCreateDataFragment(); | |
| } | |
| EmitDataMappingSymbol(); | |
| MCELFStreamer::EmitValueImpl(Value, Size, Loc); | |
| } | |
| void EmitAssemblerFlag(MCAssemblerFlag Flag) override { | |
| MCELFStreamer::EmitAssemblerFlag(Flag); | |
| switch (Flag) { | |
| case MCAF_SyntaxUnified: | |
| return; // no-op here. | |
| case MCAF_Code16: | |
| IsThumb = true; | |
| return; // Change to Thumb mode | |
| case MCAF_Code32: | |
| IsThumb = false; | |
| return; // Change to ARM mode | |
| case MCAF_Code64: | |
| return; | |
| case MCAF_SubsectionsViaSymbols: | |
| return; | |
| } | |
| } | |
| private: | |
| enum ElfMappingSymbol { | |
| EMS_None, | |
| EMS_ARM, | |
| EMS_Thumb, | |
| EMS_Data | |
| }; | |
| struct ElfMappingSymbolInfo { | |
| explicit ElfMappingSymbolInfo(SMLoc Loc, MCFragment *F, uint64_t O) | |
| : Loc(Loc), F(F), Offset(O), State(EMS_None) {} | |
| void resetInfo() { | |
| F = nullptr; | |
| Offset = 0; | |
| } | |
| bool hasInfo() { return F != nullptr; } | |
| SMLoc Loc; | |
| MCFragment *F; | |
| uint64_t Offset; | |
| ElfMappingSymbol State; | |
| }; | |
| void EmitDataMappingSymbol() { | |
| if (LastEMSInfo->State == EMS_Data) | |
| return; | |
| else if (LastEMSInfo->State == EMS_None) { | |
| // This is a tentative symbol, it won't really be emitted until it's | |
| // actually needed. | |
| ElfMappingSymbolInfo *EMS = LastEMSInfo.get(); | |
| auto *DF = dyn_cast_or_null<MCDataFragment>(getCurrentFragment()); | |
| if (!DF) | |
| return; | |
| EMS->Loc = SMLoc(); | |
| EMS->F = getCurrentFragment(); | |
| EMS->Offset = DF->getContents().size(); | |
| LastEMSInfo->State = EMS_Data; | |
| return; | |
| } | |
| EmitMappingSymbol("$d"); | |
| LastEMSInfo->State = EMS_Data; | |
| } | |
| void EmitThumbMappingSymbol() { | |
| if (LastEMSInfo->State == EMS_Thumb) | |
| return; | |
| FlushPendingMappingSymbol(); | |
| EmitMappingSymbol("$t"); | |
| LastEMSInfo->State = EMS_Thumb; | |
| } | |
| void EmitARMMappingSymbol() { | |
| if (LastEMSInfo->State == EMS_ARM) | |
| return; | |
| FlushPendingMappingSymbol(); | |
| EmitMappingSymbol("$a"); | |
| LastEMSInfo->State = EMS_ARM; | |
| } | |
| void EmitMappingSymbol(StringRef Name) { | |
| auto *Symbol = cast<MCSymbolELF>(getContext().getOrCreateSymbol( | |
| Name + "." + Twine(MappingSymbolCounter++))); | |
| EmitLabel(Symbol); | |
| Symbol->setType(ELF::STT_NOTYPE); | |
| Symbol->setBinding(ELF::STB_LOCAL); | |
| Symbol->setExternal(false); | |
| } | |
| void EmitMappingSymbol(StringRef Name, SMLoc Loc, MCFragment *F, | |
| uint64_t Offset) { | |
| auto *Symbol = cast<MCSymbolELF>(getContext().getOrCreateSymbol( | |
| Name + "." + Twine(MappingSymbolCounter++))); | |
| EmitLabelAtPos(Symbol, Loc, F, Offset); | |
| Symbol->setType(ELF::STT_NOTYPE); | |
| Symbol->setBinding(ELF::STB_LOCAL); | |
| Symbol->setExternal(false); | |
| } | |
| void EmitThumbFunc(MCSymbol *Func) override { | |
| getAssembler().setIsThumbFunc(Func); | |
| EmitSymbolAttribute(Func, MCSA_ELF_TypeFunction); | |
| } | |
| // Helper functions for ARM exception handling directives | |
| void EHReset(); | |
| // Reset state between object emissions | |
| void reset() override; | |
| void EmitPersonalityFixup(StringRef Name); | |
| void FlushPendingOffset(); | |
| void FlushUnwindOpcodes(bool NoHandlerData); | |
| void SwitchToEHSection(StringRef Prefix, unsigned Type, unsigned Flags, | |
| SectionKind Kind, const MCSymbol &Fn); | |
| void SwitchToExTabSection(const MCSymbol &FnStart); | |
| void SwitchToExIdxSection(const MCSymbol &FnStart); | |
| void EmitFixup(const MCExpr *Expr, MCFixupKind Kind); | |
| bool IsThumb; | |
| bool IsAndroid; | |
| int64_t MappingSymbolCounter = 0; | |
| DenseMap<const MCSection *, std::unique_ptr<ElfMappingSymbolInfo>> | |
| LastMappingSymbols; | |
| std::unique_ptr<ElfMappingSymbolInfo> LastEMSInfo; | |
| // ARM Exception Handling Frame Information | |
| MCSymbol *ExTab; | |
| MCSymbol *FnStart; | |
| const MCSymbol *Personality; | |
| unsigned PersonalityIndex; | |
| unsigned FPReg; // Frame pointer register | |
| int64_t FPOffset; // Offset: (final frame pointer) - (initial $sp) | |
| int64_t SPOffset; // Offset: (final $sp) - (initial $sp) | |
| int64_t PendingOffset; // Offset: (final $sp) - (emitted $sp) | |
| bool UsedFP; | |
| bool CantUnwind; | |
| SmallVector<uint8_t, 64> Opcodes; | |
| UnwindOpcodeAssembler UnwindOpAsm; | |
| }; | |
| } // end anonymous namespace | |
| ARMELFStreamer &ARMTargetELFStreamer::getStreamer() { | |
| return static_cast<ARMELFStreamer &>(Streamer); | |
| } | |
| void ARMTargetELFStreamer::emitFnStart() { getStreamer().emitFnStart(); } | |
| void ARMTargetELFStreamer::emitFnEnd() { getStreamer().emitFnEnd(); } | |
| void ARMTargetELFStreamer::emitCantUnwind() { getStreamer().emitCantUnwind(); } | |
| void ARMTargetELFStreamer::emitPersonality(const MCSymbol *Personality) { | |
| getStreamer().emitPersonality(Personality); | |
| } | |
| void ARMTargetELFStreamer::emitPersonalityIndex(unsigned Index) { | |
| getStreamer().emitPersonalityIndex(Index); | |
| } | |
| void ARMTargetELFStreamer::emitHandlerData() { | |
| getStreamer().emitHandlerData(); | |
| } | |
| void ARMTargetELFStreamer::emitSetFP(unsigned FpReg, unsigned SpReg, | |
| int64_t Offset) { | |
| getStreamer().emitSetFP(FpReg, SpReg, Offset); | |
| } | |
| void ARMTargetELFStreamer::emitMovSP(unsigned Reg, int64_t Offset) { | |
| getStreamer().emitMovSP(Reg, Offset); | |
| } | |
| void ARMTargetELFStreamer::emitPad(int64_t Offset) { | |
| getStreamer().emitPad(Offset); | |
| } | |
| void ARMTargetELFStreamer::emitRegSave(const SmallVectorImpl<unsigned> &RegList, | |
| bool isVector) { | |
| getStreamer().emitRegSave(RegList, isVector); | |
| } | |
| void ARMTargetELFStreamer::emitUnwindRaw(int64_t Offset, | |
| const SmallVectorImpl<uint8_t> &Opcodes) { | |
| getStreamer().emitUnwindRaw(Offset, Opcodes); | |
| } | |
| void ARMTargetELFStreamer::switchVendor(StringRef Vendor) { | |
| assert(!Vendor.empty() && "Vendor cannot be empty."); | |
| if (CurrentVendor == Vendor) | |
| return; | |
| if (!CurrentVendor.empty()) | |
| finishAttributeSection(); | |
| assert(Contents.empty() && | |
| ".ARM.attributes should be flushed before changing vendor"); | |
| CurrentVendor = Vendor; | |
| } | |
| void ARMTargetELFStreamer::emitAttribute(unsigned Attribute, unsigned Value) { | |
| setAttributeItem(Attribute, Value, /* OverwriteExisting= */ true); | |
| } | |
| void ARMTargetELFStreamer::emitTextAttribute(unsigned Attribute, | |
| StringRef Value) { | |
| setAttributeItem(Attribute, Value, /* OverwriteExisting= */ true); | |
| } | |
| void ARMTargetELFStreamer::emitIntTextAttribute(unsigned Attribute, | |
| unsigned IntValue, | |
| StringRef StringValue) { | |
| setAttributeItems(Attribute, IntValue, StringValue, | |
| /* OverwriteExisting= */ true); | |
| } | |
| void ARMTargetELFStreamer::emitArch(ARM::ArchKind Value) { | |
| Arch = Value; | |
| } | |
| void ARMTargetELFStreamer::emitObjectArch(ARM::ArchKind Value) { | |
| EmittedArch = Value; | |
| } | |
| void ARMTargetELFStreamer::emitArchDefaultAttributes() { | |
| using namespace ARMBuildAttrs; | |
| setAttributeItem(CPU_name, | |
| ARM::getCPUAttr(Arch), | |
| false); | |
| if (EmittedArch == ARM::ArchKind::INVALID) | |
| setAttributeItem(CPU_arch, | |
| ARM::getArchAttr(Arch), | |
| false); | |
| else | |
| setAttributeItem(CPU_arch, | |
| ARM::getArchAttr(EmittedArch), | |
| false); | |
| switch (Arch) { | |
| case ARM::ArchKind::ARMV2: | |
| case ARM::ArchKind::ARMV2A: | |
| case ARM::ArchKind::ARMV3: | |
| case ARM::ArchKind::ARMV3M: | |
| case ARM::ArchKind::ARMV4: | |
| setAttributeItem(ARM_ISA_use, Allowed, false); | |
| break; | |
| case ARM::ArchKind::ARMV4T: | |
| case ARM::ArchKind::ARMV5T: | |
| case ARM::ArchKind::ARMV5TE: | |
| case ARM::ArchKind::ARMV6: | |
| setAttributeItem(ARM_ISA_use, Allowed, false); | |
| setAttributeItem(THUMB_ISA_use, Allowed, false); | |
| break; | |
| case ARM::ArchKind::ARMV6T2: | |
| setAttributeItem(ARM_ISA_use, Allowed, false); | |
| setAttributeItem(THUMB_ISA_use, AllowThumb32, false); | |
| break; | |
| case ARM::ArchKind::ARMV6K: | |
| case ARM::ArchKind::ARMV6KZ: | |
| setAttributeItem(ARM_ISA_use, Allowed, false); | |
| setAttributeItem(THUMB_ISA_use, Allowed, false); | |
| setAttributeItem(Virtualization_use, AllowTZ, false); | |
| break; | |
| case ARM::ArchKind::ARMV6M: | |
| setAttributeItem(THUMB_ISA_use, Allowed, false); | |
| break; | |
| case ARM::ArchKind::ARMV7A: | |
| setAttributeItem(CPU_arch_profile, ApplicationProfile, false); | |
| setAttributeItem(ARM_ISA_use, Allowed, false); | |
| setAttributeItem(THUMB_ISA_use, AllowThumb32, false); | |
| break; | |
| case ARM::ArchKind::ARMV7R: | |
| setAttributeItem(CPU_arch_profile, RealTimeProfile, false); | |
| setAttributeItem(ARM_ISA_use, Allowed, false); | |
| setAttributeItem(THUMB_ISA_use, AllowThumb32, false); | |
| break; | |
| case ARM::ArchKind::ARMV7EM: | |
| case ARM::ArchKind::ARMV7M: | |
| setAttributeItem(CPU_arch_profile, MicroControllerProfile, false); | |
| setAttributeItem(THUMB_ISA_use, AllowThumb32, false); | |
| break; | |
| case ARM::ArchKind::ARMV8A: | |
| case ARM::ArchKind::ARMV8_1A: | |
| case ARM::ArchKind::ARMV8_2A: | |
| case ARM::ArchKind::ARMV8_3A: | |
| case ARM::ArchKind::ARMV8_4A: | |
| case ARM::ArchKind::ARMV8_5A: | |
| setAttributeItem(CPU_arch_profile, ApplicationProfile, false); | |
| setAttributeItem(ARM_ISA_use, Allowed, false); | |
| setAttributeItem(THUMB_ISA_use, AllowThumb32, false); | |
| setAttributeItem(MPextension_use, Allowed, false); | |
| setAttributeItem(Virtualization_use, AllowTZVirtualization, false); | |
| break; | |
| case ARM::ArchKind::ARMV8MBaseline: | |
| case ARM::ArchKind::ARMV8MMainline: | |
| setAttributeItem(THUMB_ISA_use, AllowThumbDerived, false); | |
| setAttributeItem(CPU_arch_profile, MicroControllerProfile, false); | |
| break; | |
| case ARM::ArchKind::IWMMXT: | |
| setAttributeItem(ARM_ISA_use, Allowed, false); | |
| setAttributeItem(THUMB_ISA_use, Allowed, false); | |
| setAttributeItem(WMMX_arch, AllowWMMXv1, false); | |
| break; | |
| case ARM::ArchKind::IWMMXT2: | |
| setAttributeItem(ARM_ISA_use, Allowed, false); | |
| setAttributeItem(THUMB_ISA_use, Allowed, false); | |
| setAttributeItem(WMMX_arch, AllowWMMXv2, false); | |
| break; | |
| default: | |
| report_fatal_error("Unknown Arch: " + Twine(ARM::getArchName(Arch))); | |
| break; | |
| } | |
| } | |
| void ARMTargetELFStreamer::emitFPU(unsigned Value) { | |
| FPU = Value; | |
| } | |
| void ARMTargetELFStreamer::emitFPUDefaultAttributes() { | |
| switch (FPU) { | |
| case ARM::FK_VFP: | |
| case ARM::FK_VFPV2: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPv2, | |
| /* OverwriteExisting= */ false); | |
| break; | |
| case ARM::FK_VFPV3: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPv3A, | |
| /* OverwriteExisting= */ false); | |
| break; | |
| case ARM::FK_VFPV3_FP16: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPv3A, | |
| /* OverwriteExisting= */ false); | |
| setAttributeItem(ARMBuildAttrs::FP_HP_extension, | |
| ARMBuildAttrs::AllowHPFP, | |
| /* OverwriteExisting= */ false); | |
| break; | |
| case ARM::FK_VFPV3_D16: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPv3B, | |
| /* OverwriteExisting= */ false); | |
| break; | |
| case ARM::FK_VFPV3_D16_FP16: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPv3B, | |
| /* OverwriteExisting= */ false); | |
| setAttributeItem(ARMBuildAttrs::FP_HP_extension, | |
| ARMBuildAttrs::AllowHPFP, | |
| /* OverwriteExisting= */ false); | |
| break; | |
| case ARM::FK_VFPV3XD: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPv3B, | |
| /* OverwriteExisting= */ false); | |
| break; | |
| case ARM::FK_VFPV3XD_FP16: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPv3B, | |
| /* OverwriteExisting= */ false); | |
| setAttributeItem(ARMBuildAttrs::FP_HP_extension, | |
| ARMBuildAttrs::AllowHPFP, | |
| /* OverwriteExisting= */ false); | |
| break; | |
| case ARM::FK_VFPV4: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPv4A, | |
| /* OverwriteExisting= */ false); | |
| break; | |
| // ABI_HardFP_use is handled in ARMAsmPrinter, so _SP_D16 is treated the same | |
| // as _D16 here. | |
| case ARM::FK_FPV4_SP_D16: | |
| case ARM::FK_VFPV4_D16: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPv4B, | |
| /* OverwriteExisting= */ false); | |
| break; | |
| case ARM::FK_FP_ARMV8: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPARMv8A, | |
| /* OverwriteExisting= */ false); | |
| break; | |
| // FPV5_D16 is identical to FP_ARMV8 except for the number of D registers, so | |
| // uses the FP_ARMV8_D16 build attribute. | |
| case ARM::FK_FPV5_SP_D16: | |
| case ARM::FK_FPV5_D16: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPARMv8B, | |
| /* OverwriteExisting= */ false); | |
| break; | |
| case ARM::FK_NEON: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPv3A, | |
| /* OverwriteExisting= */ false); | |
| setAttributeItem(ARMBuildAttrs::Advanced_SIMD_arch, | |
| ARMBuildAttrs::AllowNeon, | |
| /* OverwriteExisting= */ false); | |
| break; | |
| case ARM::FK_NEON_FP16: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPv3A, | |
| /* OverwriteExisting= */ false); | |
| setAttributeItem(ARMBuildAttrs::Advanced_SIMD_arch, | |
| ARMBuildAttrs::AllowNeon, | |
| /* OverwriteExisting= */ false); | |
| setAttributeItem(ARMBuildAttrs::FP_HP_extension, | |
| ARMBuildAttrs::AllowHPFP, | |
| /* OverwriteExisting= */ false); | |
| break; | |
| case ARM::FK_NEON_VFPV4: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPv4A, | |
| /* OverwriteExisting= */ false); | |
| setAttributeItem(ARMBuildAttrs::Advanced_SIMD_arch, | |
| ARMBuildAttrs::AllowNeon2, | |
| /* OverwriteExisting= */ false); | |
| break; | |
| case ARM::FK_NEON_FP_ARMV8: | |
| case ARM::FK_CRYPTO_NEON_FP_ARMV8: | |
| setAttributeItem(ARMBuildAttrs::FP_arch, | |
| ARMBuildAttrs::AllowFPARMv8A, | |
| /* OverwriteExisting= */ false); | |
| // 'Advanced_SIMD_arch' must be emitted not here, but within | |
| // ARMAsmPrinter::emitAttributes(), depending on hasV8Ops() and hasV8_1a() | |
| break; | |
| case ARM::FK_SOFTVFP: | |
| case ARM::FK_NONE: | |
| break; | |
| default: | |
| report_fatal_error("Unknown FPU: " + Twine(FPU)); | |
| break; | |
| } | |
| } | |
| size_t ARMTargetELFStreamer::calculateContentSize() const { | |
| size_t Result = 0; | |
| for (size_t i = 0; i < Contents.size(); ++i) { | |
| AttributeItem item = Contents[i]; | |
| switch (item.Type) { | |
| case AttributeItem::HiddenAttribute: | |
| break; | |
| case AttributeItem::NumericAttribute: | |
| Result += getULEB128Size(item.Tag); | |
| Result += getULEB128Size(item.IntValue); | |
| break; | |
| case AttributeItem::TextAttribute: | |
| Result += getULEB128Size(item.Tag); | |
| Result += item.StringValue.size() + 1; // string + '\0' | |
| break; | |
| case AttributeItem::NumericAndTextAttributes: | |
| Result += getULEB128Size(item.Tag); | |
| Result += getULEB128Size(item.IntValue); | |
| Result += item.StringValue.size() + 1; // string + '\0'; | |
| break; | |
| } | |
| } | |
| return Result; | |
| } | |
| void ARMTargetELFStreamer::finishAttributeSection() { | |
| // <format-version> | |
| // [ <section-length> "vendor-name" | |
| // [ <file-tag> <size> <attribute>* | |
| // | <section-tag> <size> <section-number>* 0 <attribute>* | |
| // | <symbol-tag> <size> <symbol-number>* 0 <attribute>* | |
| // ]+ | |
| // ]* | |
| if (FPU != ARM::FK_INVALID) | |
| emitFPUDefaultAttributes(); | |
| if (Arch != ARM::ArchKind::INVALID) | |
| emitArchDefaultAttributes(); | |
| if (Contents.empty()) | |
| return; | |
| llvm::sort(Contents, AttributeItem::LessTag); | |
| ARMELFStreamer &Streamer = getStreamer(); | |
| // Switch to .ARM.attributes section | |
| if (AttributeSection) { | |
| Streamer.SwitchSection(AttributeSection); | |
| } else { | |
| AttributeSection = Streamer.getContext().getELFSection( | |
| ".ARM.attributes", ELF::SHT_ARM_ATTRIBUTES, 0); | |
| Streamer.SwitchSection(AttributeSection); | |
| // Format version | |
| Streamer.EmitIntValue(0x41, 1); | |
| } | |
| // Vendor size + Vendor name + '\0' | |
| const size_t VendorHeaderSize = 4 + CurrentVendor.size() + 1; | |
| // Tag + Tag Size | |
| const size_t TagHeaderSize = 1 + 4; | |
| const size_t ContentsSize = calculateContentSize(); | |
| Streamer.EmitIntValue(VendorHeaderSize + TagHeaderSize + ContentsSize, 4); | |
| Streamer.EmitBytes(CurrentVendor); | |
| Streamer.EmitIntValue(0, 1); // '\0' | |
| Streamer.EmitIntValue(ARMBuildAttrs::File, 1); | |
| Streamer.EmitIntValue(TagHeaderSize + ContentsSize, 4); | |
| // Size should have been accounted for already, now | |
| // emit each field as its type (ULEB or String) | |
| for (size_t i = 0; i < Contents.size(); ++i) { | |
| AttributeItem item = Contents[i]; | |
| Streamer.EmitULEB128IntValue(item.Tag); | |
| switch (item.Type) { | |
| default: llvm_unreachable("Invalid attribute type"); | |
| case AttributeItem::NumericAttribute: | |
| Streamer.EmitULEB128IntValue(item.IntValue); | |
| break; | |
| case AttributeItem::TextAttribute: | |
| Streamer.EmitBytes(item.StringValue); | |
| Streamer.EmitIntValue(0, 1); // '\0' | |
| break; | |
| case AttributeItem::NumericAndTextAttributes: | |
| Streamer.EmitULEB128IntValue(item.IntValue); | |
| Streamer.EmitBytes(item.StringValue); | |
| Streamer.EmitIntValue(0, 1); // '\0' | |
| break; | |
| } | |
| } | |
| Contents.clear(); | |
| FPU = ARM::FK_INVALID; | |
| } | |
| void ARMTargetELFStreamer::emitLabel(MCSymbol *Symbol) { | |
| ARMELFStreamer &Streamer = getStreamer(); | |
| if (!Streamer.IsThumb) | |
| return; | |
| Streamer.getAssembler().registerSymbol(*Symbol); | |
| unsigned Type = cast<MCSymbolELF>(Symbol)->getType(); | |
| if (Type == ELF::STT_FUNC || Type == ELF::STT_GNU_IFUNC) | |
| Streamer.EmitThumbFunc(Symbol); | |
| } | |
| void | |
| ARMTargetELFStreamer::AnnotateTLSDescriptorSequence(const MCSymbolRefExpr *S) { | |
| getStreamer().EmitFixup(S, FK_Data_4); | |
| } | |
| void ARMTargetELFStreamer::emitThumbSet(MCSymbol *Symbol, const MCExpr *Value) { | |
| if (const MCSymbolRefExpr *SRE = dyn_cast<MCSymbolRefExpr>(Value)) { | |
| const MCSymbol &Sym = SRE->getSymbol(); | |
| if (!Sym.isDefined()) { | |
| getStreamer().EmitAssignment(Symbol, Value); | |
| return; | |
| } | |
| } | |
| getStreamer().EmitThumbFunc(Symbol); | |
| getStreamer().EmitAssignment(Symbol, Value); | |
| } | |
| void ARMTargetELFStreamer::emitInst(uint32_t Inst, char Suffix) { | |
| getStreamer().emitInst(Inst, Suffix); | |
| } | |
| void ARMTargetELFStreamer::reset() { AttributeSection = nullptr; } | |
| void ARMELFStreamer::FinishImpl() { | |
| MCTargetStreamer &TS = *getTargetStreamer(); | |
| ARMTargetStreamer &ATS = static_cast<ARMTargetStreamer &>(TS); | |
| ATS.finishAttributeSection(); | |
| MCELFStreamer::FinishImpl(); | |
| } | |
| void ARMELFStreamer::reset() { | |
| MCTargetStreamer &TS = *getTargetStreamer(); | |
| ARMTargetStreamer &ATS = static_cast<ARMTargetStreamer &>(TS); | |
| ATS.reset(); | |
| MappingSymbolCounter = 0; | |
| MCELFStreamer::reset(); | |
| LastMappingSymbols.clear(); | |
| LastEMSInfo.reset(); | |
| // MCELFStreamer clear's the assembler's e_flags. However, for | |
| // arm we manually set the ABI version on streamer creation, so | |
| // do the same here | |
| getAssembler().setELFHeaderEFlags(ELF::EF_ARM_EABI_VER5); | |
| } | |
| inline void ARMELFStreamer::SwitchToEHSection(StringRef Prefix, | |
| unsigned Type, | |
| unsigned Flags, | |
| SectionKind Kind, | |
| const MCSymbol &Fn) { | |
| const MCSectionELF &FnSection = | |
| static_cast<const MCSectionELF &>(Fn.getSection()); | |
| // Create the name for new section | |
| StringRef FnSecName(FnSection.getSectionName()); | |
| SmallString<128> EHSecName(Prefix); | |
| if (FnSecName != ".text") { | |
| EHSecName += FnSecName; | |
| } | |
| // Get .ARM.extab or .ARM.exidx section | |
| const MCSymbolELF *Group = FnSection.getGroup(); | |
| if (Group) | |
| Flags |= ELF::SHF_GROUP; | |
| MCSectionELF *EHSection = getContext().getELFSection( | |
| EHSecName, Type, Flags, 0, Group, FnSection.getUniqueID(), | |
| static_cast<const MCSymbolELF *>(&Fn)); | |
| assert(EHSection && "Failed to get the required EH section"); | |
| // Switch to .ARM.extab or .ARM.exidx section | |
| SwitchSection(EHSection); | |
| EmitCodeAlignment(4); | |
| } | |
| inline void ARMELFStreamer::SwitchToExTabSection(const MCSymbol &FnStart) { | |
| SwitchToEHSection(".ARM.extab", ELF::SHT_PROGBITS, ELF::SHF_ALLOC, | |
| SectionKind::getData(), FnStart); | |
| } | |
| inline void ARMELFStreamer::SwitchToExIdxSection(const MCSymbol &FnStart) { | |
| SwitchToEHSection(".ARM.exidx", ELF::SHT_ARM_EXIDX, | |
| ELF::SHF_ALLOC | ELF::SHF_LINK_ORDER, | |
| SectionKind::getData(), FnStart); | |
| } | |
| void ARMELFStreamer::EmitFixup(const MCExpr *Expr, MCFixupKind Kind) { | |
| MCDataFragment *Frag = getOrCreateDataFragment(); | |
| Frag->getFixups().push_back(MCFixup::create(Frag->getContents().size(), Expr, | |
| Kind)); | |
| } | |
| void ARMELFStreamer::EHReset() { | |
| ExTab = nullptr; | |
| FnStart = nullptr; | |
| Personality = nullptr; | |
| PersonalityIndex = ARM::EHABI::NUM_PERSONALITY_INDEX; | |
| FPReg = ARM::SP; | |
| FPOffset = 0; | |
| SPOffset = 0; | |
| PendingOffset = 0; | |
| UsedFP = false; | |
| CantUnwind = false; | |
| Opcodes.clear(); | |
| UnwindOpAsm.Reset(); | |
| } | |
| void ARMELFStreamer::emitFnStart() { | |
| assert(FnStart == nullptr); | |
| FnStart = getContext().createTempSymbol(); | |
| EmitLabel(FnStart); | |
| } | |
| void ARMELFStreamer::emitFnEnd() { | |
| assert(FnStart && ".fnstart must precedes .fnend"); | |
| // Emit unwind opcodes if there is no .handlerdata directive | |
| if (!ExTab && !CantUnwind) | |
| FlushUnwindOpcodes(true); | |
| // Emit the exception index table entry | |
| SwitchToExIdxSection(*FnStart); | |
| // The EHABI requires a dependency preserving R_ARM_NONE relocation to the | |
| // personality routine to protect it from an arbitrary platform's static | |
| // linker garbage collection. We disable this for Android where the unwinder | |
| // is either dynamically linked or directly references the personality | |
| // routine. | |
| if (PersonalityIndex < ARM::EHABI::NUM_PERSONALITY_INDEX && !IsAndroid) | |
| EmitPersonalityFixup(GetAEABIUnwindPersonalityName(PersonalityIndex)); | |
| const MCSymbolRefExpr *FnStartRef = | |
| MCSymbolRefExpr::create(FnStart, | |
| MCSymbolRefExpr::VK_ARM_PREL31, | |
| getContext()); | |
| EmitValue(FnStartRef, 4); | |
| if (CantUnwind) { | |
| EmitIntValue(ARM::EHABI::EXIDX_CANTUNWIND, 4); | |
| } else if (ExTab) { | |
| // Emit a reference to the unwind opcodes in the ".ARM.extab" section. | |
| const MCSymbolRefExpr *ExTabEntryRef = | |
| MCSymbolRefExpr::create(ExTab, | |
| MCSymbolRefExpr::VK_ARM_PREL31, | |
| getContext()); | |
| EmitValue(ExTabEntryRef, 4); | |
| } else { | |
| // For the __aeabi_unwind_cpp_pr0, we have to emit the unwind opcodes in | |
| // the second word of exception index table entry. The size of the unwind | |
| // opcodes should always be 4 bytes. | |
| assert(PersonalityIndex == ARM::EHABI::AEABI_UNWIND_CPP_PR0 && | |
| "Compact model must use __aeabi_unwind_cpp_pr0 as personality"); | |
| assert(Opcodes.size() == 4u && | |
| "Unwind opcode size for __aeabi_unwind_cpp_pr0 must be equal to 4"); | |
| uint64_t Intval = Opcodes[0] | | |
| Opcodes[1] << 8 | | |
| Opcodes[2] << 16 | | |
| Opcodes[3] << 24; | |
| EmitIntValue(Intval, Opcodes.size()); | |
| } | |
| // Switch to the section containing FnStart | |
| SwitchSection(&FnStart->getSection()); | |
| // Clean exception handling frame information | |
| EHReset(); | |
| } | |
| void ARMELFStreamer::emitCantUnwind() { CantUnwind = true; } | |
| // Add the R_ARM_NONE fixup at the same position | |
| void ARMELFStreamer::EmitPersonalityFixup(StringRef Name) { | |
| const MCSymbol *PersonalitySym = getContext().getOrCreateSymbol(Name); | |
| const MCSymbolRefExpr *PersonalityRef = MCSymbolRefExpr::create( | |
| PersonalitySym, MCSymbolRefExpr::VK_ARM_NONE, getContext()); | |
| visitUsedExpr(*PersonalityRef); | |
| MCDataFragment *DF = getOrCreateDataFragment(); | |
| DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), | |
| PersonalityRef, | |
| MCFixup::getKindForSize(4, false))); | |
| } | |
| void ARMELFStreamer::FlushPendingOffset() { | |
| if (PendingOffset != 0) { | |
| UnwindOpAsm.EmitSPOffset(-PendingOffset); | |
| PendingOffset = 0; | |
| } | |
| } | |
| void ARMELFStreamer::FlushUnwindOpcodes(bool NoHandlerData) { | |
| // Emit the unwind opcode to restore $sp. | |
| if (UsedFP) { | |
| const MCRegisterInfo *MRI = getContext().getRegisterInfo(); | |
| int64_t LastRegSaveSPOffset = SPOffset - PendingOffset; | |
| UnwindOpAsm.EmitSPOffset(LastRegSaveSPOffset - FPOffset); | |
| UnwindOpAsm.EmitSetSP(MRI->getEncodingValue(FPReg)); | |
| } else { | |
| FlushPendingOffset(); | |
| } | |
| // Finalize the unwind opcode sequence | |
| UnwindOpAsm.Finalize(PersonalityIndex, Opcodes); | |
| // For compact model 0, we have to emit the unwind opcodes in the .ARM.exidx | |
| // section. Thus, we don't have to create an entry in the .ARM.extab | |
| // section. | |
| if (NoHandlerData && PersonalityIndex == ARM::EHABI::AEABI_UNWIND_CPP_PR0) | |
| return; | |
| // Switch to .ARM.extab section. | |
| SwitchToExTabSection(*FnStart); | |
| // Create .ARM.extab label for offset in .ARM.exidx | |
| assert(!ExTab); | |
| ExTab = getContext().createTempSymbol(); | |
| EmitLabel(ExTab); | |
| // Emit personality | |
| if (Personality) { | |
| const MCSymbolRefExpr *PersonalityRef = | |
| MCSymbolRefExpr::create(Personality, | |
| MCSymbolRefExpr::VK_ARM_PREL31, | |
| getContext()); | |
| EmitValue(PersonalityRef, 4); | |
| } | |
| // Emit unwind opcodes | |
| assert((Opcodes.size() % 4) == 0 && | |
| "Unwind opcode size for __aeabi_cpp_unwind_pr0 must be multiple of 4"); | |
| for (unsigned I = 0; I != Opcodes.size(); I += 4) { | |
| uint64_t Intval = Opcodes[I] | | |
| Opcodes[I + 1] << 8 | | |
| Opcodes[I + 2] << 16 | | |
| Opcodes[I + 3] << 24; | |
| EmitIntValue(Intval, 4); | |
| } | |
| // According to ARM EHABI section 9.2, if the __aeabi_unwind_cpp_pr1() or | |
| // __aeabi_unwind_cpp_pr2() is used, then the handler data must be emitted | |
| // after the unwind opcodes. The handler data consists of several 32-bit | |
| // words, and should be terminated by zero. | |
| // | |
| // In case that the .handlerdata directive is not specified by the | |
| // programmer, we should emit zero to terminate the handler data. | |
| if (NoHandlerData && !Personality) | |
| EmitIntValue(0, 4); | |
| } | |
| void ARMELFStreamer::emitHandlerData() { FlushUnwindOpcodes(false); } | |
| void ARMELFStreamer::emitPersonality(const MCSymbol *Per) { | |
| Personality = Per; | |
| UnwindOpAsm.setPersonality(Per); | |
| } | |
| void ARMELFStreamer::emitPersonalityIndex(unsigned Index) { | |
| assert(Index < ARM::EHABI::NUM_PERSONALITY_INDEX && "invalid index"); | |
| PersonalityIndex = Index; | |
| } | |
| void ARMELFStreamer::emitSetFP(unsigned NewFPReg, unsigned NewSPReg, | |
| int64_t Offset) { | |
| assert((NewSPReg == ARM::SP || NewSPReg == FPReg) && | |
| "the operand of .setfp directive should be either $sp or $fp"); | |
| UsedFP = true; | |
| FPReg = NewFPReg; | |
| if (NewSPReg == ARM::SP) | |
| FPOffset = SPOffset + Offset; | |
| else | |
| FPOffset += Offset; | |
| } | |
| void ARMELFStreamer::emitMovSP(unsigned Reg, int64_t Offset) { | |
| assert((Reg != ARM::SP && Reg != ARM::PC) && | |
| "the operand of .movsp cannot be either sp or pc"); | |
| assert(FPReg == ARM::SP && "current FP must be SP"); | |
| FlushPendingOffset(); | |
| FPReg = Reg; | |
| FPOffset = SPOffset + Offset; | |
| const MCRegisterInfo *MRI = getContext().getRegisterInfo(); | |
| UnwindOpAsm.EmitSetSP(MRI->getEncodingValue(FPReg)); | |
| } | |
| void ARMELFStreamer::emitPad(int64_t Offset) { | |
| // Track the change of the $sp offset | |
| SPOffset -= Offset; | |
| // To squash multiple .pad directives, we should delay the unwind opcode | |
| // until the .save, .vsave, .handlerdata, or .fnend directives. | |
| PendingOffset -= Offset; | |
| } | |
| void ARMELFStreamer::emitRegSave(const SmallVectorImpl<unsigned> &RegList, | |
| bool IsVector) { | |
| // Collect the registers in the register list | |
| unsigned Count = 0; | |
| uint32_t Mask = 0; | |
| const MCRegisterInfo *MRI = getContext().getRegisterInfo(); | |
| for (size_t i = 0; i < RegList.size(); ++i) { | |
| unsigned Reg = MRI->getEncodingValue(RegList[i]); | |
| assert(Reg < (IsVector ? 32U : 16U) && "Register out of range"); | |
| unsigned Bit = (1u << Reg); | |
| if ((Mask & Bit) == 0) { | |
| Mask |= Bit; | |
| ++Count; | |
| } | |
| } | |
| // Track the change the $sp offset: For the .save directive, the | |
| // corresponding push instruction will decrease the $sp by (4 * Count). | |
| // For the .vsave directive, the corresponding vpush instruction will | |
| // decrease $sp by (8 * Count). | |
| SPOffset -= Count * (IsVector ? 8 : 4); | |
| // Emit the opcode | |
| FlushPendingOffset(); | |
| if (IsVector) | |
| UnwindOpAsm.EmitVFPRegSave(Mask); | |
| else | |
| UnwindOpAsm.EmitRegSave(Mask); | |
| } | |
| void ARMELFStreamer::emitUnwindRaw(int64_t Offset, | |
| const SmallVectorImpl<uint8_t> &Opcodes) { | |
| FlushPendingOffset(); | |
| SPOffset = SPOffset - Offset; | |
| UnwindOpAsm.EmitRaw(Opcodes); | |
| } | |
| namespace llvm { | |
| MCTargetStreamer *createARMTargetAsmStreamer(MCStreamer &S, | |
| formatted_raw_ostream &OS, | |
| MCInstPrinter *InstPrint, | |
| bool isVerboseAsm) { | |
| return new ARMTargetAsmStreamer(S, OS, *InstPrint, isVerboseAsm); | |
| } | |
| MCTargetStreamer *createARMNullTargetStreamer(MCStreamer &S) { | |
| return new ARMTargetStreamer(S); | |
| } | |
| MCTargetStreamer *createARMObjectTargetStreamer(MCStreamer &S, | |
| const MCSubtargetInfo &STI) { | |
| const Triple &TT = STI.getTargetTriple(); | |
| if (TT.isOSBinFormatELF()) | |
| return new ARMTargetELFStreamer(S); | |
| return new ARMTargetStreamer(S); | |
| } | |
| MCELFStreamer *createARMELFStreamer(MCContext &Context, | |
| std::unique_ptr<MCAsmBackend> TAB, | |
| std::unique_ptr<MCObjectWriter> OW, | |
| std::unique_ptr<MCCodeEmitter> Emitter, | |
| bool RelaxAll, bool IsThumb, | |
| bool IsAndroid) { | |
| ARMELFStreamer *S = | |
| new ARMELFStreamer(Context, std::move(TAB), std::move(OW), | |
| std::move(Emitter), IsThumb, IsAndroid); | |
| // FIXME: This should eventually end up somewhere else where more | |
| // intelligent flag decisions can be made. For now we are just maintaining | |
| // the status quo for ARM and setting EF_ARM_EABI_VER5 as the default. | |
| S->getAssembler().setELFHeaderEFlags(ELF::EF_ARM_EABI_VER5); | |
| if (RelaxAll) | |
| S->getAssembler().setRelaxAll(true); | |
| return S; | |
| } | |
| } // end namespace llvm |