1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-24 19:52:54 +01:00

[MCStreamer] Move emission of attributes section into MCELFStreamer

Enable the emission of a GNU attributes section by reusing the code for
emitting the ARM build attributes section.

The GNU attributes follow the exact same section format as the ARM
BuildAttributes section, so this can be factored out and reused for GNU
attributes generally.

The immediate motivation for this is to emit a GNU attributes section for the
vector ABI on SystemZ (https://reviews.llvm.org/D105067).

Review: Logan Chien, Ulrich Weigand

Differential Revision: https://reviews.llvm.org/D102894
This commit is contained in:
Jonas Paulsson 2021-06-28 18:18:25 -05:00
parent cc12b285b6
commit 38b768656f
7 changed files with 347 additions and 289 deletions

View File

@ -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 @@ public:
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<AttributeItem, 64> 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<AttributeItem, 64> &AttrsVec);
void createAttributesSection(StringRef Vendor, const Twine &Section,
unsigned Type, MCSection *&AttributeSection,
SmallVector<AttributeItem, 64> &AttrsVec);
// GNU attributes that will get emitted at the end of the asm file.
SmallVector<AttributeItem, 64> 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;

View File

@ -337,6 +337,9 @@ public:
/// \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

View File

@ -618,6 +618,9 @@ public:
/// \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.

View File

@ -153,6 +153,8 @@ public:
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 @@ void MCAsmStreamer::emitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) {
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;

View File

@ -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 <cassert>
@ -697,6 +698,13 @@ void MCELFStreamer::emitBundleUnlock() {
}
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 @@ void MCELFStreamer::emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
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<AttributeItem, 64> &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<AttributeItem, 64> &AttrsVec) {
// <format-version>
// [ <section-length> "vendor-name"
// [ <file-tag> <size> <attribute>*
// | <section-tag> <size> <section-number>* 0 <attribute>*
// | <symbol-tag> <size> <symbol-number>* 0 <attribute>*
// ]+
// ]*
// 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<MCAsmBackend> &&MAB,
std::unique_ptr<MCObjectWriter> &&OW,

View File

@ -140,6 +140,25 @@ bool MCAsmParser::parseExpression(const MCExpr *&Res) {
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)

View File

@ -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 <algorithm>
@ -274,104 +273,13 @@ void ARMTargetAsmStreamer::emitUnwindRaw(int64_t Offset,
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,
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 @@ private:
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 @@ void ARMTargetELFStreamer::switchVendor(StringRef Vendor) {
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::emitObjectArch(ARM::ArchKind Value) {
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 @@ void ARMTargetELFStreamer::emitArchDefaultAttributes() {
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 @@ void ARMTargetELFStreamer::emitArchDefaultAttributes() {
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 @@ void ARMTargetELFStreamer::emitArchDefaultAttributes() {
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::emitFPU(unsigned Value) {
}
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 @@ void ARMTargetELFStreamer::emitFPUDefaultAttributes() {
}
}
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>*
// ]+
// ]*
ARMELFStreamer &S = getStreamer();
if (FPU != ARM::FK_INVALID)
emitFPUDefaultAttributes();
@ -1089,63 +944,30 @@ void ARMTargetELFStreamer::finishAttributeSection() {
if (Arch != ARM::ArchKind::INVALID)
emitArchDefaultAttributes();
if (Contents.empty())
if (S.Contents.empty())
return;
llvm::sort(Contents, AttributeItem::LessTag);
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);
ARMELFStreamer &Streamer = getStreamer();
S.emitAttributesSection(CurrentVendor, ".ARM.attributes",
ELF::SHT_ARM_ATTRIBUTES, AttributeSection);
// 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);
// 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;
}
}
Contents.clear();
FPU = ARM::FK_INVALID;
}