[Arm] Fix parsing and emission of Tag_also_compatible_with eabi attribute

According to the ABI for the Arm Architecture, the value for the
Tag_also_compatible_with eabi attribute is represented by an NTBS entry.
This string value, in turn, is composed of a pair of tag+value encoded
in one of two formats:
- ULEB128: tag, ULEB128: value, 0.
- ULEB128: tag, NBTS: data.
(See [[ 60a8eb8c55/addenda32/addenda32.rst (3373secondary-compatibility-tag) | section 3.3.7.3 on the Addenda to, and Errata in, the ABI for the Arm Architecture ]].)

Currently the Arm assembly parser and streamer ignore the encoding of
the attribute's NTBS value, which can result in incorrect attributes
being emitted in both assembly and object file outputs.

This patch fixes these issues by properly handing the value's encoding.
An update to llvm-readobj to properly handle the attribute's value will be
covered by a separate patch.

Patch by Victor Campos and Lucas Prates.

Reviewed By: vhscampos

Differential Revision: https://reviews.llvm.org/D129500
This commit is contained in:
Lucas Prates 2022-07-11 17:33:48 +01:00
parent f96e159321
commit ba9caf9170
6 changed files with 72 additions and 10 deletions

View File

@ -263,6 +263,8 @@ enum {
PACRETUsed = 1
};
std::string encodeAttrTagValuePair(StringRef OriginalString);
} // namespace ARMBuildAttrs
} // namespace llvm

View File

@ -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 <iomanip>
#include <sstream>
using namespace llvm;
@ -71,3 +76,39 @@ constexpr TagNameMap ARMAttributeTags{tagData};
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<const uint8_t *>(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;
}

View File

@ -11439,12 +11439,20 @@ bool ARMAsmParser::parseDirectiveEabiAttr(SMLoc L) {
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())

View File

@ -202,7 +202,12 @@ void ARMTargetAsmStreamer::emitTextAttribute(unsigned Attribute,
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());

View File

@ -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: )

View File

@ -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