diff --git a/llvm/include/llvm/MC/MCELFStreamer.h b/llvm/include/llvm/MC/MCELFStreamer.h --- a/llvm/include/llvm/MC/MCELFStreamer.h +++ b/llvm/include/llvm/MC/MCELFStreamer.h @@ -10,6 +10,7 @@ #define LLVM_MC_MCELFSTREAMER_H #include "llvm/ADT/SmallVector.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCObjectStreamer.h" @@ -79,6 +80,52 @@ void emitBundleLock(bool AlignToEnd) override; void emitBundleUnlock() override; + /// ELF object attributes section emission support + struct AttributeItem { + // 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. + enum { + HiddenAttribute = 0, + NumericAttribute, + TextAttribute, + NumericAndTextAttributes + } Type; + unsigned Tag; + unsigned IntValue; + std::string StringValue; + }; + + // Attributes that are added and managed entirely by target. + SmallVector Contents; + void setAttributeItem(unsigned Attribute, unsigned Value, + bool OverwriteExisting); + void setAttributeItem(unsigned Attribute, StringRef Value, + bool OverwriteExisting); + void setAttributeItems(unsigned Attribute, unsigned IntValue, + StringRef StringValue, bool OverwriteExisting); + void emitAttributesSection(StringRef Vendor, const Twine &Section, + unsigned Type, MCSection *&AttributeSection) { + createAttributesSection(Vendor, Section, Type, AttributeSection, Contents); + } + +private: + AttributeItem *getAttributeItem(unsigned Attribute); + size_t calculateContentSize(SmallVector &AttrsVec); + void createAttributesSection(StringRef Vendor, const Twine &Section, + unsigned Type, MCSection *&AttributeSection, + SmallVector &AttrsVec); + + // GNU attributes that will get emitted at the end of the asm file. + SmallVector GNUAttributes; + +public: + void emitGNUAttribute(unsigned Tag, unsigned Value) override { + AttributeItem Item = {AttributeItem::NumericAttribute, Tag, Value, + std::string(StringRef(""))}; + GNUAttributes.push_back(Item); + } + private: bool isBundleLocked() const; void emitInstToFragment(const MCInst &Inst, const MCSubtargetInfo &) override; diff --git a/llvm/include/llvm/MC/MCParser/MCAsmParser.h b/llvm/include/llvm/MC/MCParser/MCAsmParser.h --- a/llvm/include/llvm/MC/MCParser/MCAsmParser.h +++ b/llvm/include/llvm/MC/MCParser/MCAsmParser.h @@ -337,6 +337,9 @@ /// \return - False on success. virtual bool parseParenExprOfDepth(unsigned ParenDepth, const MCExpr *&Res, SMLoc &EndLoc) = 0; + + /// Parse a .gnu_attribute. + bool parseGNUAttribute(SMLoc L, int64_t &Tag, int64_t &IntegerValue); }; /// Create an MCAsmParser instance for parsing assembly similar to gas syntax diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -618,6 +618,9 @@ /// \param Args - Arguments of the LOH. virtual void emitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) {} + /// Emit a .gnu_attribute directive. + virtual void emitGNUAttribute(unsigned Tag, unsigned Value) {} + /// Emit a common symbol. /// /// \param Symbol - The common symbol to emit. diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -153,6 +153,8 @@ void emitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) override; + void emitGNUAttribute(unsigned Tag, unsigned Value) override; + StringRef getMnemonic(MCInst &MI) override { return InstPrinter->getMnemonic(&MI).first; } @@ -538,6 +540,10 @@ EmitEOL(); } +void MCAsmStreamer::emitGNUAttribute(unsigned Tag, unsigned Value) { + OS << "\t.gnu_attribute " << Tag << ", " << Value << "\n"; +} + void MCAsmStreamer::emitAssemblerFlag(MCAssemblerFlag Flag) { switch (Flag) { case MCAF_SyntaxUnified: OS << "\t.syntax unified"; break; diff --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp --- a/llvm/lib/MC/MCELFStreamer.cpp +++ b/llvm/lib/MC/MCELFStreamer.cpp @@ -31,6 +31,7 @@ #include "llvm/MC/MCSymbolELF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include @@ -697,6 +698,13 @@ } void MCELFStreamer::finishImpl() { + // Emit the .gnu attributes section if any attributes have been added. + if (!GNUAttributes.empty()) { + MCSection *DummyAttributeSection = nullptr; + createAttributesSection("gnu", ".gnu.attributes", ELF::SHT_GNU_ATTRIBUTES, + DummyAttributeSection, GNUAttributes); + } + // Ensure the last section gets aligned if necessary. MCSection *CurSection = getCurrentSectionOnly(); setSectionAlignmentForBundling(getAssembler(), CurSection); @@ -726,6 +734,156 @@ llvm_unreachable("ELF doesn't support this directive"); } +void MCELFStreamer::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, + std::string(StringRef(""))}; + Contents.push_back(Item); +} + +void MCELFStreamer::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 = std::string(Value); + return; + } + + // Create new attribute item + AttributeItem Item = {AttributeItem::TextAttribute, Attribute, 0, + std::string(Value)}; + Contents.push_back(Item); +} + +void MCELFStreamer::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 = std::string(StringValue); + return; + } + + // Create new attribute item + AttributeItem Item = {AttributeItem::NumericAndTextAttributes, Attribute, + IntValue, std::string(StringValue)}; + Contents.push_back(Item); +} + +MCELFStreamer::AttributeItem * +MCELFStreamer::getAttributeItem(unsigned Attribute) { + for (size_t I = 0; I < Contents.size(); ++I) + if (Contents[I].Tag == Attribute) + return &Contents[I]; + return nullptr; +} + +size_t +MCELFStreamer::calculateContentSize(SmallVector &AttrsVec) { + size_t Result = 0; + for (size_t I = 0; I < AttrsVec.size(); ++I) { + AttributeItem Item = AttrsVec[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 MCELFStreamer::createAttributesSection( + StringRef Vendor, const Twine &Section, unsigned Type, + MCSection *&AttributeSection, SmallVector &AttrsVec) { + // + // [ "vendor-name" + // [ * + // | * 0 * + // | * 0 * + // ]+ + // ]* + + // Switch section to AttributeSection or get/create the section. + if (AttributeSection) { + SwitchSection(AttributeSection); + } else { + AttributeSection = getContext().getELFSection(Section, Type, 0); + SwitchSection(AttributeSection); + + // Format version + emitInt8(0x41); + } + + // Vendor size + Vendor name + '\0' + const size_t VendorHeaderSize = 4 + Vendor.size() + 1; + + // Tag + Tag Size + const size_t TagHeaderSize = 1 + 4; + + const size_t ContentsSize = calculateContentSize(AttrsVec); + + emitInt32(VendorHeaderSize + TagHeaderSize + ContentsSize); + emitBytes(Vendor); + emitInt8(0); // '\0' + + emitInt8(ARMBuildAttrs::File); + emitInt32(TagHeaderSize + ContentsSize); + + // Size should have been accounted for already, now + // emit each field as its type (ULEB or String) + for (size_t I = 0; I < AttrsVec.size(); ++I) { + AttributeItem Item = AttrsVec[I]; + emitULEB128IntValue(Item.Tag); + switch (Item.Type) { + default: + llvm_unreachable("Invalid attribute type"); + case AttributeItem::NumericAttribute: + emitULEB128IntValue(Item.IntValue); + break; + case AttributeItem::TextAttribute: + emitBytes(Item.StringValue); + emitInt8(0); // '\0' + break; + case AttributeItem::NumericAndTextAttributes: + emitULEB128IntValue(Item.IntValue); + emitBytes(Item.StringValue); + emitInt8(0); // '\0' + break; + } + } + + AttrsVec.clear(); +} + MCStreamer *llvm::createELFStreamer(MCContext &Context, std::unique_ptr &&MAB, std::unique_ptr &&OW, diff --git a/llvm/lib/MC/MCParser/MCAsmParser.cpp b/llvm/lib/MC/MCParser/MCAsmParser.cpp --- a/llvm/lib/MC/MCParser/MCAsmParser.cpp +++ b/llvm/lib/MC/MCParser/MCAsmParser.cpp @@ -140,6 +140,25 @@ return parseExpression(Res, L); } +bool MCAsmParser::parseGNUAttribute(SMLoc L, int64_t &Tag, + int64_t &IntegerValue) { + // Parse a .gnu_attribute with numerical tag and value. + StringRef S(L.getPointer()); + SMLoc TagLoc; + TagLoc = getTok().getLoc(); + const AsmToken &Tok = getTok(); + if (Tok.isNot(AsmToken::Integer)) + return false; + Tag = Tok.getIntVal(); + Lex(); // Eat the Tag + Lex(); // Eat the comma + if (Tok.isNot(AsmToken::Integer)) + return false; + IntegerValue = Tok.getIntVal(); + Lex(); // Eat the IntegerValue + return true; +} + void MCParsedAsmOperand::dump() const { // Cannot completely remove virtual function even in release mode. #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -46,7 +46,6 @@ #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 @@ -274,104 +273,13 @@ 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 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, - std::string(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 = std::string(Value); - return; - } - - // Create new attribute item - AttributeItem Item = {AttributeItem::TextAttribute, Attribute, 0, - std::string(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 = std::string(StringValue); - return; - } - - // Create new attribute item - AttributeItem Item = {AttributeItem::NumericAndTextAttributes, Attribute, - IntValue, std::string(StringValue)}; - Contents.push_back(Item); - } - void emitArchDefaultAttributes(); void emitFPUDefaultAttributes(); @@ -406,8 +314,6 @@ 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; @@ -777,26 +683,28 @@ if (!CurrentVendor.empty()) finishAttributeSection(); - assert(Contents.empty() && + assert(getStreamer().Contents.empty() && ".ARM.attributes should be flushed before changing vendor"); CurrentVendor = Vendor; } void ARMTargetELFStreamer::emitAttribute(unsigned Attribute, unsigned Value) { - setAttributeItem(Attribute, Value, /* OverwriteExisting= */ true); + getStreamer().setAttributeItem(Attribute, Value, + /* OverwriteExisting= */ true); } void ARMTargetELFStreamer::emitTextAttribute(unsigned Attribute, StringRef Value) { - setAttributeItem(Attribute, Value, /* OverwriteExisting= */ true); + getStreamer().setAttributeItem(Attribute, Value, + /* OverwriteExisting= */ true); } void ARMTargetELFStreamer::emitIntTextAttribute(unsigned Attribute, unsigned IntValue, StringRef StringValue) { - setAttributeItems(Attribute, IntValue, StringValue, - /* OverwriteExisting= */ true); + getStreamer().setAttributeItems(Attribute, IntValue, StringValue, + /* OverwriteExisting= */ true); } void ARMTargetELFStreamer::emitArch(ARM::ArchKind Value) { @@ -809,19 +717,14 @@ void ARMTargetELFStreamer::emitArchDefaultAttributes() { using namespace ARMBuildAttrs; + ARMELFStreamer &S = getStreamer(); - setAttributeItem(CPU_name, - ARM::getCPUAttr(Arch), - false); + S.setAttributeItem(CPU_name, ARM::getCPUAttr(Arch), false); if (EmittedArch == ARM::ArchKind::INVALID) - setAttributeItem(CPU_arch, - ARM::getArchAttr(Arch), - false); + S.setAttributeItem(CPU_arch, ARM::getArchAttr(Arch), false); else - setAttributeItem(CPU_arch, - ARM::getArchAttr(EmittedArch), - false); + S.setAttributeItem(CPU_arch, ARM::getArchAttr(EmittedArch), false); switch (Arch) { case ARM::ArchKind::ARMV2: @@ -829,7 +732,7 @@ case ARM::ArchKind::ARMV3: case ARM::ArchKind::ARMV3M: case ARM::ArchKind::ARMV4: - setAttributeItem(ARM_ISA_use, Allowed, false); + S.setAttributeItem(ARM_ISA_use, Allowed, false); break; case ARM::ArchKind::ARMV4T: @@ -837,42 +740,42 @@ case ARM::ArchKind::XSCALE: case ARM::ArchKind::ARMV5TE: case ARM::ArchKind::ARMV6: - setAttributeItem(ARM_ISA_use, Allowed, false); - setAttributeItem(THUMB_ISA_use, Allowed, false); + S.setAttributeItem(ARM_ISA_use, Allowed, false); + S.setAttributeItem(THUMB_ISA_use, Allowed, false); break; case ARM::ArchKind::ARMV6T2: - setAttributeItem(ARM_ISA_use, Allowed, false); - setAttributeItem(THUMB_ISA_use, AllowThumb32, false); + S.setAttributeItem(ARM_ISA_use, Allowed, false); + S.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); + S.setAttributeItem(ARM_ISA_use, Allowed, false); + S.setAttributeItem(THUMB_ISA_use, Allowed, false); + S.setAttributeItem(Virtualization_use, AllowTZ, false); break; case ARM::ArchKind::ARMV6M: - setAttributeItem(THUMB_ISA_use, Allowed, false); + S.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); + S.setAttributeItem(CPU_arch_profile, ApplicationProfile, false); + S.setAttributeItem(ARM_ISA_use, Allowed, false); + S.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); + S.setAttributeItem(CPU_arch_profile, RealTimeProfile, false); + S.setAttributeItem(ARM_ISA_use, Allowed, false); + S.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); + S.setAttributeItem(CPU_arch_profile, MicroControllerProfile, false); + S.setAttributeItem(THUMB_ISA_use, AllowThumb32, false); break; case ARM::ArchKind::ARMV8A: @@ -882,29 +785,29 @@ case ARM::ArchKind::ARMV8_4A: case ARM::ArchKind::ARMV8_5A: case ARM::ArchKind::ARMV8_6A: - 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); + S.setAttributeItem(CPU_arch_profile, ApplicationProfile, false); + S.setAttributeItem(ARM_ISA_use, Allowed, false); + S.setAttributeItem(THUMB_ISA_use, AllowThumb32, false); + S.setAttributeItem(MPextension_use, Allowed, false); + S.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); + S.setAttributeItem(THUMB_ISA_use, AllowThumbDerived, false); + S.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); + S.setAttributeItem(ARM_ISA_use, Allowed, false); + S.setAttributeItem(THUMB_ISA_use, Allowed, false); + S.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); + S.setAttributeItem(ARM_ISA_use, Allowed, false); + S.setAttributeItem(THUMB_ISA_use, Allowed, false); + S.setAttributeItem(WMMX_arch, AllowWMMXv2, false); break; default: @@ -918,123 +821,106 @@ } void ARMTargetELFStreamer::emitFPUDefaultAttributes() { + ARMELFStreamer &S = getStreamer(); + switch (FPU) { case ARM::FK_VFP: case ARM::FK_VFPV2: - setAttributeItem(ARMBuildAttrs::FP_arch, - ARMBuildAttrs::AllowFPv2, - /* OverwriteExisting= */ false); + S.setAttributeItem(ARMBuildAttrs::FP_arch, ARMBuildAttrs::AllowFPv2, + /* OverwriteExisting= */ false); break; case ARM::FK_VFPV3: - setAttributeItem(ARMBuildAttrs::FP_arch, - ARMBuildAttrs::AllowFPv3A, - /* OverwriteExisting= */ false); + S.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); + S.setAttributeItem(ARMBuildAttrs::FP_arch, ARMBuildAttrs::AllowFPv3A, + /* OverwriteExisting= */ false); + S.setAttributeItem(ARMBuildAttrs::FP_HP_extension, ARMBuildAttrs::AllowHPFP, + /* OverwriteExisting= */ false); break; case ARM::FK_VFPV3_D16: - setAttributeItem(ARMBuildAttrs::FP_arch, - ARMBuildAttrs::AllowFPv3B, - /* OverwriteExisting= */ false); + S.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); + S.setAttributeItem(ARMBuildAttrs::FP_arch, ARMBuildAttrs::AllowFPv3B, + /* OverwriteExisting= */ false); + S.setAttributeItem(ARMBuildAttrs::FP_HP_extension, ARMBuildAttrs::AllowHPFP, + /* OverwriteExisting= */ false); break; case ARM::FK_VFPV3XD: - setAttributeItem(ARMBuildAttrs::FP_arch, - ARMBuildAttrs::AllowFPv3B, - /* OverwriteExisting= */ false); + S.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); + S.setAttributeItem(ARMBuildAttrs::FP_arch, ARMBuildAttrs::AllowFPv3B, + /* OverwriteExisting= */ false); + S.setAttributeItem(ARMBuildAttrs::FP_HP_extension, ARMBuildAttrs::AllowHPFP, + /* OverwriteExisting= */ false); break; case ARM::FK_VFPV4: - setAttributeItem(ARMBuildAttrs::FP_arch, - ARMBuildAttrs::AllowFPv4A, - /* OverwriteExisting= */ false); + S.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); + S.setAttributeItem(ARMBuildAttrs::FP_arch, ARMBuildAttrs::AllowFPv4B, + /* OverwriteExisting= */ false); break; case ARM::FK_FP_ARMV8: - setAttributeItem(ARMBuildAttrs::FP_arch, - ARMBuildAttrs::AllowFPARMv8A, - /* OverwriteExisting= */ false); + S.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); + S.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); + S.setAttributeItem(ARMBuildAttrs::FP_arch, ARMBuildAttrs::AllowFPv3A, + /* OverwriteExisting= */ false); + S.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); + S.setAttributeItem(ARMBuildAttrs::FP_arch, ARMBuildAttrs::AllowFPv3A, + /* OverwriteExisting= */ false); + S.setAttributeItem(ARMBuildAttrs::Advanced_SIMD_arch, + ARMBuildAttrs::AllowNeon, + /* OverwriteExisting= */ false); + S.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); + S.setAttributeItem(ARMBuildAttrs::FP_arch, ARMBuildAttrs::AllowFPv4A, + /* OverwriteExisting= */ false); + S.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); + S.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; @@ -1049,39 +935,8 @@ } } -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() { - // - // [ "vendor-name" - // [ * - // | * 0 * - // | * 0 * - // ]+ - // ]* + ARMELFStreamer &S = getStreamer(); if (FPU != ARM::FK_INVALID) emitFPUDefaultAttributes(); @@ -1089,63 +944,30 @@ if (Arch != ARM::ArchKind::INVALID) emitArchDefaultAttributes(); - if (Contents.empty()) + if (S.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.emitInt8(0x41); - } - - // 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.emitInt32(VendorHeaderSize + TagHeaderSize + ContentsSize); - Streamer.emitBytes(CurrentVendor); - Streamer.emitInt8(0); // '\0' - - Streamer.emitInt8(ARMBuildAttrs::File); - Streamer.emitInt32(TagHeaderSize + ContentsSize); + auto LessTag = [](const MCELFStreamer::AttributeItem &LHS, + const MCELFStreamer::AttributeItem &RHS) -> bool { + // 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)); + }; + llvm::sort(S.Contents, LessTag); - // 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.emitInt8(0); // '\0' - break; - case AttributeItem::NumericAndTextAttributes: - Streamer.emitULEB128IntValue(item.IntValue); - Streamer.emitBytes(item.StringValue); - Streamer.emitInt8(0); // '\0' - break; - } - } + S.emitAttributesSection(CurrentVendor, ".ARM.attributes", + ELF::SHT_ARM_ATTRIBUTES, AttributeSection); - Contents.clear(); FPU = ARM::FK_INVALID; }