diff --git a/llvm/include/llvm/Support/ARMBuildAttributes.h b/llvm/include/llvm/Support/ARMBuildAttributes.h --- a/llvm/include/llvm/Support/ARMBuildAttributes.h +++ b/llvm/include/llvm/Support/ARMBuildAttributes.h @@ -263,6 +263,8 @@ PACRETUsed = 1 }; +std::string encodeAttrTagValuePair(StringRef OriginalString); + } // namespace ARMBuildAttrs } // namespace llvm diff --git a/llvm/lib/Support/ARMBuildAttrs.cpp b/llvm/lib/Support/ARMBuildAttrs.cpp --- a/llvm/lib/Support/ARMBuildAttrs.cpp +++ b/llvm/lib/Support/ARMBuildAttrs.cpp @@ -7,6 +7,11 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/ARMBuildAttributes.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/LEB128.h" +#include +#include using namespace llvm; @@ -71,3 +76,39 @@ const TagNameMap &llvm::ARMBuildAttrs::getARMAttributeTags() { return ARMAttributeTags; } + +static std::string getEncodedULEB128AsText(const uint8_t *Value, + unsigned Size) { + std::stringstream SS; + for (unsigned i = 0; i < Size; ++i) { + SS << "\\" << std::setfill('0') << std::setw(3) << std::oct + << int(Value[i]); + } + return SS.str(); +} + +std::string +llvm::ARMBuildAttrs::encodeAttrTagValuePair(StringRef OriginalString) { + auto BytesBegin = reinterpret_cast(OriginalString.data()); + auto BytesEnd = BytesBegin + OriginalString.size(); + + unsigned N = 0; + const char *Error = nullptr; + unsigned Tag = decodeULEB128(BytesBegin, &N, BytesEnd, &Error); + if (Error) + report_fatal_error("Could not decode Tag value: " + Twine(Error)); + + std::string EncodedPair = getEncodedULEB128AsText(BytesBegin, N); + switch (Tag) { + case ARMBuildAttrs::CPU_raw_name: + case ARMBuildAttrs::CPU_name: + case ARMBuildAttrs::compatibility: + case ARMBuildAttrs::conformance: + EncodedPair += OriginalString.substr(N); + break; + default: + EncodedPair += + getEncodedULEB128AsText(BytesBegin + N, OriginalString.size() - N); + } + return EncodedPair; +} diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -11439,12 +11439,20 @@ return true; } + std::string EscapedValue; if (IsStringValue) { if (Parser.getTok().isNot(AsmToken::String)) return Error(Parser.getTok().getLoc(), "bad string constant"); - StringValue = Parser.getTok().getStringContents(); - Parser.Lex(); + if (Tag == ARMBuildAttrs::also_compatible_with) { + if (Parser.parseEscapedString(EscapedValue)) + return Error(Parser.getTok().getLoc(), "bad escaped string constant"); + + StringValue = EscapedValue; + } else { + StringValue = Parser.getTok().getStringContents(); + Parser.Lex(); + } } if (Parser.parseEOL()) 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 @@ -202,7 +202,12 @@ OS << "\t.cpu\t" << String.lower(); break; default: - OS << "\t.eabi_attribute\t" << Attribute << ", \"" << String << "\""; + OS << "\t.eabi_attribute\t" << Attribute << ", \""; + if (Attribute == ARMBuildAttrs::also_compatible_with) + OS << ARMBuildAttrs::encodeAttrTagValuePair(String); + else + OS << String; + OS << "\""; if (IsVerboseAsm) { StringRef Name = ELFAttrs::attrTypeAsString( Attribute, ARMBuildAttrs::getARMAttributeTags()); diff --git a/llvm/test/CodeGen/ARM/build-attributes-encoding.s b/llvm/test/CodeGen/ARM/build-attributes-encoding.s --- a/llvm/test/CodeGen/ARM/build-attributes-encoding.s +++ b/llvm/test/CodeGen/ARM/build-attributes-encoding.s @@ -63,6 +63,9 @@ // Tag_BTI_extension (=52) .eabi_attribute 52, 0 +// Tag_also_compatible_with (=65) +.eabi_attribute 65, "\006\017" + // Tag_BTI_use (=74) .eabi_attribute 74, 0 @@ -86,16 +89,16 @@ // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 // CHECK-NEXT: Offset: 0x34 -// CHECK-NEXT: Size: 81 +// CHECK-NEXT: Size: 85 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 1 // CHECK-NEXT: EntrySize: 0 // CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 41500000 00616561 62690001 46000000 |AP...aeabi..F...| +// CHECK-NEXT: 0000: 41540000 00616561 62690001 4A000000 |AT...aeabi..J...| // CHECK-NEXT: 0010: 05636F72 7465782D 61380006 0A074108 |.cortex-a8....A.| // CHECK-NEXT: 0020: 0109020A 030C0214 01150117 01180119 |................| // CHECK-NEXT: 0030: 011B001C 0124012A 012C022E 01320034 |.....$.*.,...2.4| -// CHECK-NEXT: 0040: 0044034A 004C006E A0018101 3100FA01 |.D.J.L.n....1...| -// CHECK-NEXT: 0050: 01 |.| +// CHECK-NEXT: 0040: 0041060F 0044034A 004C006E A0018101 |.A...D.J.L.n....| +// CHECK-NEXT: 0050: 3100FA01 01 |1....| // CHECK-NEXT: ) diff --git a/llvm/test/MC/ARM/directive-eabi_attribute.s b/llvm/test/MC/ARM/directive-eabi_attribute.s --- a/llvm/test/MC/ARM/directive-eabi_attribute.s +++ b/llvm/test/MC/ARM/directive-eabi_attribute.s @@ -233,11 +233,14 @@ @ CHECK-OBJ-NEXT: Value: 0 @ CHECK-OBJ-NEXT: TagName: nodefaults @ CHECK-OBJ-NEXT: Description: Unspecified Tags UNDEFINED - .eabi_attribute Tag_also_compatible_with, "gnu" -@ CHECK: .eabi_attribute 65, "gnu" + .eabi_attribute Tag_also_compatible_with, "\006\017" +@ The value for Tag_also_compatible_with should be a pair of a tag (ULEB128) + +@ a value (ULEB128 + null or NTBS). llvm-readobj doesn't now how to process +@ this yet, so we use the encoded value explicitly here. +@ CHECK: .eabi_attribute 65, "\006\017" @ CHECK-OBJ: Tag: 65 @ CHECK-OBJ-NEXT: TagName: also_compatible_with -@ CHECK-OBJ-NEXT: Value: gnu +@ CHECK-OBJ-NEXT: Value: .eabi_attribute Tag_T2EE_use, 0 @ CHECK: .eabi_attribute 66, 0 @ CHECK-OBJ: Tag: 66