Skip to content

Commit d52675e

Browse files
[lld][AArch64][Build Attributes] Add support for AArch64 Build Attributes (llvm#147970)
This patch enables lld to read AArch64 Build Attributes and convert them into GNU Properties. Changes: - Parses AArch64 Build Attributes from input object files. - Converts known attributes into corresponding GNU Properties. - Merges attributes when linking multiple objects. Spec reference: https://github.com/ARM-software/abi-aa/pull/230/files#r1030 Co-authored-by: Sivan Shani <sivan.shani@arm.com> --------- Co-authored-by: Sivan Shani <sivan.shani@arm.com>
1 parent a073cbb commit d52675e

9 files changed

+311
-24
lines changed

lld/ELF/InputFiles.cpp

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/ADT/STLExtras.h"
2222
#include "llvm/LTO/LTO.h"
2323
#include "llvm/Object/IRObjectFile.h"
24+
#include "llvm/Support/AArch64AttributeParser.h"
2425
#include "llvm/Support/ARMAttributeParser.h"
2526
#include "llvm/Support/ARMBuildAttributes.h"
2627
#include "llvm/Support/Endian.h"
@@ -537,6 +538,41 @@ uint32_t ObjFile<ELFT>::getSectionIndex(const Elf_Sym &sym) const {
537538
this);
538539
}
539540

541+
template <class ELFT>
542+
static void
543+
handleAArch64BAAndGnuProperties(ObjFile<ELFT> *file, Ctx &ctx,
544+
const AArch64BuildAttrSubsections &baInfo) {
545+
if (file->aarch64PauthAbiCoreInfo) {
546+
// Check for data mismatch.
547+
if (file->aarch64PauthAbiCoreInfo) {
548+
if (baInfo.Pauth.TagPlatform != file->aarch64PauthAbiCoreInfo->platform ||
549+
baInfo.Pauth.TagSchema != file->aarch64PauthAbiCoreInfo->version)
550+
Err(ctx) << file
551+
<< " GNU properties and build attributes have conflicting "
552+
"AArch64 PAuth data";
553+
}
554+
if (baInfo.AndFeatures != file->andFeatures)
555+
Err(ctx) << file
556+
<< " GNU properties and build attributes have conflicting "
557+
"AArch64 PAuth data";
558+
} else {
559+
// When BuildAttributes are missing, PauthABI value defaults to (TagPlatform
560+
// = 0, TagSchema = 0). GNU properties do not write PAuthAbiCoreInfo if GNU
561+
// property is not present. To match this behaviour, we only write
562+
// PAuthAbiCoreInfo when there is at least one non-zero value. The
563+
// specification reserves TagPlatform = 0, TagSchema = 1 values to match the
564+
// 'Invalid' GNU property section with platform = 0, version = 0.
565+
if (baInfo.Pauth.TagPlatform || baInfo.Pauth.TagSchema) {
566+
if (baInfo.Pauth.TagPlatform == 0 && baInfo.Pauth.TagSchema == 1)
567+
file->aarch64PauthAbiCoreInfo = {0, 0};
568+
else
569+
file->aarch64PauthAbiCoreInfo = {baInfo.Pauth.TagPlatform,
570+
baInfo.Pauth.TagSchema};
571+
}
572+
file->andFeatures = baInfo.AndFeatures;
573+
}
574+
}
575+
540576
template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
541577
object::ELFFile<ELFT> obj = this->getObj();
542578
// Read a section table. justSymbols is usually false.
@@ -554,6 +590,7 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
554590
sections.resize(size);
555591
for (size_t i = 0; i != size; ++i) {
556592
const Elf_Shdr &sec = objSections[i];
593+
557594
if (LLVM_LIKELY(sec.sh_type == SHT_PROGBITS))
558595
continue;
559596
if (LLVM_LIKELY(sec.sh_type == SHT_GROUP)) {
@@ -637,13 +674,6 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
637674
}
638675
break;
639676
case EM_AARCH64:
640-
// FIXME: BuildAttributes have been implemented in llvm, but not yet in
641-
// lld. Remove the section so that it does not accumulate in the output
642-
// file. When support is implemented we expect not to output a build
643-
// attributes section in files of type ET_EXEC or ET_SHARED, but ld -r
644-
// ouptut will need a single merged attributes section.
645-
if (sec.sh_type == SHT_AARCH64_ATTRIBUTES)
646-
sections[i] = &InputSection::discarded;
647677
// Producing a static binary with MTE globals is not currently supported,
648678
// remove all SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections as they're unused
649679
// medatada, and we don't want them to end up in the output file for
@@ -744,6 +774,8 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
744774
StringRef shstrtab = CHECK2(obj.getSectionStringTable(objSections), this);
745775
uint64_t size = objSections.size();
746776
SmallVector<ArrayRef<Elf_Word>, 0> selectedGroups;
777+
AArch64BuildAttrSubsections aarch64BAsubSections;
778+
bool hasAArch64BuildAttributes = false;
747779
for (size_t i = 0; i != size; ++i) {
748780
if (this->sections[i] == &InputSection::discarded)
749781
continue;
@@ -775,6 +807,26 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
775807
continue;
776808
}
777809

810+
// Processor-specific types that do not use the following switch statement.
811+
//
812+
// Extract Build Attributes section contents into aarch64BAsubSections.
813+
// Input objects may contain both build Build Attributes and GNU
814+
// properties. We delay processing Build Attributes until we have finished
815+
// reading all sections so that we can check that these are consistent.
816+
if (type == SHT_AARCH64_ATTRIBUTES && ctx.arg.emachine == EM_AARCH64) {
817+
ArrayRef<uint8_t> contents = check(obj.getSectionContents(sec));
818+
AArch64AttributeParser attributes;
819+
if (Error e = attributes.parse(contents, ELFT::Endianness)) {
820+
StringRef name = check(obj.getSectionName(sec, shstrtab));
821+
InputSection isec(*this, sec, name);
822+
Warn(ctx) << &isec << ": " << std::move(e);
823+
} else {
824+
aarch64BAsubSections = extractBuildAttributesSubsections(attributes);
825+
hasAArch64BuildAttributes = true;
826+
}
827+
this->sections[i] = &InputSection::discarded;
828+
continue;
829+
}
778830
switch (type) {
779831
case SHT_GROUP: {
780832
if (!ctx.arg.relocatable)
@@ -912,6 +964,12 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
912964
<< linkSec;
913965
}
914966

967+
// Handle AArch64 Build Attributes and GNU properties:
968+
// - Err on mismatched values.
969+
// - Store missing values as GNU properties.
970+
if (hasAArch64BuildAttributes)
971+
handleAArch64BAAndGnuProperties<ELFT>(this, ctx, aarch64BAsubSections);
972+
915973
for (ArrayRef<Elf_Word> entries : selectedGroups)
916974
handleSectionGroup<ELFT>(this->sections, entries);
917975
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// REQUIRES: aarch64
2+
// RUN: llvm-mc -triple=aarch64_be %s -filetype=obj -o %t.o
3+
// RUN: ld.lld %t.o --shared -o %t.so
4+
// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
5+
6+
// RUN: llvm-mc -triple=aarch64_be %s -filetype=obj -o %t.o
7+
// RUN: ld.lld %t.o --shared -o %t.so
8+
// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
9+
// RUN: ld.lld %t.o -o %t
10+
// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
11+
// RUN: ld.lld -r %t.o -o %t2.o
12+
// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
13+
14+
/// Test that lld can read big-endian build-attributes.
15+
16+
// NOTE: Displaying notes found in: .note.gnu.property
17+
// NOTE-NEXT: Owner Data size Description
18+
// NOTE-NEXT: GNU 0x00000028 NT_GNU_PROPERTY_TYPE_0 (property note)
19+
// NOTE-NEXT: Properties: aarch64 feature: BTI, PAC, GCS
20+
// NOTE-NEXT: AArch64 PAuth ABI core info: platform 0x89abcdef (unknown), version 0x89abcdef
21+
22+
23+
.aeabi_subsection aeabi_pauthabi, required, uleb128
24+
.aeabi_attribute Tag_PAuth_Platform, 0x123456789ABCDEF
25+
.aeabi_attribute Tag_PAuth_Schema, 0x123456789ABCDEF
26+
.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
27+
.aeabi_attribute Tag_Feature_BTI, 1
28+
.aeabi_attribute Tag_Feature_PAC, 1
29+
.aeabi_attribute Tag_Feature_GCS, 1
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// REQUIRES: aarch64
2+
3+
// RUN: llvm-mc -triple=aarch64 %s -filetype=obj -o %t.o
4+
// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR
5+
6+
// ERR: GNU properties and build attributes have conflicting AArch64 PAuth data
7+
// ERR-NEXT: GNU properties and build attributes have conflicting AArch64 PAuth data
8+
9+
.aeabi_subsection aeabi_pauthabi, required, uleb128
10+
.aeabi_attribute Tag_PAuth_Platform, 5
11+
.aeabi_attribute Tag_PAuth_Schema, 5
12+
.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
13+
.aeabi_attribute Tag_Feature_BTI, 1
14+
.aeabi_attribute Tag_Feature_PAC, 1
15+
.aeabi_attribute Tag_Feature_GCS, 1
16+
17+
.section ".note.gnu.property", "a"
18+
.long 0x4
19+
.long 0x10
20+
.long 0x5
21+
.asciz "GNU"
22+
.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
23+
.long 0x4
24+
.long 0x2 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC
25+
.long 0x0
26+
27+
.section ".note.gnu.property", "a"
28+
.long 0x4
29+
.long 0x18
30+
.long 0x5
31+
.asciz "GNU"
32+
.long 0xc0000001
33+
.long 0x10
34+
.quad 0x12345678 // platform
35+
.quad 0x87654321 // version
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// REQUIRES: aarch64
2+
3+
// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t.o
4+
// RUN: ld.lld -r %t.o -o %t.invalid.o
5+
// RUN: llvm-readelf -n %t.invalid.o | FileCheck %s
6+
7+
/// According to the BuildAttributes specification Build Attributes
8+
/// A (TagPlatform, TagSchema)of (0, 1) maps to an explicit PAuth property
9+
/// of platform = 0, version = 0 ('Invalid').
10+
11+
// CHECK: Displaying notes found in: .note.gnu.property
12+
// CHECK-NEXT: Owner Data size Description
13+
// CHECK-NEXT: GNU 0x00000018 NT_GNU_PROPERTY_TYPE_0 (property note)
14+
// CHECK-NEXT: Properties: AArch64 PAuth ABI core info: platform 0x0 (invalid), version 0x0
15+
16+
.aeabi_subsection aeabi_pauthabi, required, uleb128
17+
.aeabi_attribute Tag_PAuth_Platform, 0
18+
.aeabi_attribute Tag_PAuth_Schema, 1
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# REQUIRES: aarch64
2+
3+
# RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t.o
4+
# RUN: ld.lld %t.o /dev/null 2>&1 | FileCheck %s
5+
6+
# CHECK: (.ARM.attributes): unexpected end of data at offset 0x3f while reading [0x3d, 0x41)
7+
8+
.section .ARM.attributes,"",%0x70000003
9+
.byte 0x41 // Tag 'A' (format version)
10+
.long 0x00000019 // Subsection length
11+
.asciz "aeabi_pauthabi" // Subsection name
12+
.byte 0x00, 0x00 // Optionality and Type
13+
.byte 0x01, 0x01, 0x02, 0x01 // PAuth_Platform and PAuth_Schema
14+
.long 0x00000023 // Subsection length
15+
.asciz "aeabi_feature_and_bits" // Subsection name
16+
.byte 0x01, 0x00 // Optionality and Type
17+
.byte 0x00, 0x01, 0x01, 0x01, 0x02, 0x01 // BTI, PAC, GCS
18+
.byte 0x00, 0x00 // This is the malformation, data is too long.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// REQUIRES: aarch64
2+
3+
// RUN: rm -rf %t && split-file %s %t && cd %t
4+
5+
// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t11.o
6+
// RUN: llvm-mc -triple=aarch64 -filetype=obj merged-property.s -o %t12.o
7+
// RUN: llvm-mc -triple=aarch64 -filetype=obj merged-property2.s -o %t13.o
8+
// RUN: ld.lld -r %t11.o %t12.o %t13.o -o %t.merged1.o
9+
// RUN: llvm-readelf -n %t.merged1.o | FileCheck %s --check-prefix=NOTE-MIXED
10+
11+
/// This test verifies merging of AArch64 build attributes and GNU property notes.
12+
/// Three object files are combined: one with build attributes (PAuth information, BTI, PAC, GCS),
13+
/// and two with GNU property notes encoding the same feature bits.
14+
/// PAuth ABI info is provided in one of the files and it is expected to be preserved in the merged output.
15+
16+
// NOTE-MIXED: Displaying notes found in: .note.gnu.property
17+
// NOTE-MIXED-NEXT: Owner Data size Description
18+
// NOTE-MIXED-NEXT: GNU 0x00000028 NT_GNU_PROPERTY_TYPE_0 (property note)
19+
// NOTE-MIXED-NEXT: Properties: aarch64 feature: BTI, PAC
20+
// NOTE-MIXED-NEXT: AArch64 PAuth ABI core info: platform 0x31 (unknown), version 0x13
21+
22+
// CHECK: .note.gnu.property
23+
// CHECK-NOT: .ARM.attributes
24+
25+
.aeabi_subsection aeabi_pauthabi, required, uleb128
26+
.aeabi_attribute Tag_PAuth_Platform, 49
27+
.aeabi_attribute Tag_PAuth_Schema, 19
28+
.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
29+
.aeabi_attribute Tag_Feature_BTI, 1
30+
.aeabi_attribute Tag_Feature_PAC, 1
31+
.aeabi_attribute Tag_Feature_GCS, 1
32+
33+
34+
//--- merged-property.s
35+
.section ".note.gnu.property", "a"
36+
.long 0x4 // Name length is always 4 ("GNU")
37+
.long end - begin // Data length
38+
.long 0x5 // Type: NT_GNU_PROPERTY_TYPE_0
39+
.asciz "GNU" // Name
40+
.p2align 0x3
41+
begin:
42+
.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
43+
.long 0x4
44+
.long 0x7 // pr_data: BTI (1), PAC (2), GCS (4) = 0b111 = 7
45+
.long 0x0
46+
// PAuth ABI property note
47+
.long 0xc0000001 // GNU_PROPERTY_AARCH64_FEATURE_PAUTH
48+
.long 0x10 // Data length
49+
.quad 0x31 // PAuth ABI platform
50+
.quad 0x13 // PAuth ABI version
51+
.p2align 0x3 // Align to 8 byte for 64 bit
52+
end:
53+
54+
//--- merged-property2.s
55+
.section .note.gnu.property, "a"
56+
.align 0x4
57+
.long 0x4 // Name length is always 4 ("GNU")
58+
.long end2 - begin2 // Data length
59+
.long 0x5 // Type: NT_GNU_PROPERTY_TYPE_0
60+
.asciz "GNU" // Name
61+
begin2:
62+
.align 0x4
63+
.long 0xc0000000 // Type: GNU_PROPERTY_AARCH64_FEATURE_1_AND
64+
.long 0x4 // Data length
65+
.long 0x7 // pr_data: BTI (1), PAC (2), GCS (4) = 0b111 = 7
66+
.long 0x0
67+
end2:
Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,50 @@
11
// REQUIRES: aarch64
2-
// RUN: llvm-mc -triple=aarch64 %s -filetype=obj -o %t.o
3-
// RUN: ld.lld %t.o --shared -o %t.so
4-
// RUN: llvm-readelf --sections %t.so | FileCheck %s
5-
// RUN: ld.lld %t.o -o %t
6-
// RUN: llvm-readelf --sections %t | FileCheck %s
7-
// RUN: ld.lld -r %t.o -o %t2.o
8-
// RUN: llvm-readelf --sections %t2.o | FileCheck %s
9-
10-
/// File has a Build attributes section. This should not appear in
11-
/// ET_EXEC or ET_SHARED files as there is no requirement for it to
12-
/// do so. FIXME, the ld -r (relocatable link) should output a single
13-
/// merged build attributes section. When full support is added in
14-
/// ld.lld this test should be updated.
2+
// RUN: rm -rf %t && split-file %s %t && cd %t
153

4+
// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t1.o
5+
// RUN: llvm-mc -triple=aarch64 -filetype=obj pauth-bti-gcs.s -o %t2.o
6+
// RUN: llvm-mc -triple=aarch64 -filetype=obj pauth-bti-pac.s -o %t3.o
7+
// RUN: ld.lld -r %t1.o %t2.o %t3.o -o %t.merged.o
8+
// RUN: llvm-readelf -n %t.merged.o | FileCheck %s --check-prefix=NOTE
9+
10+
/// This test merges three object files with AArch64 build attributes.
11+
/// All contain identical PAuth ABI info (platform/version), which must be preserved.
12+
/// Only BTI is common across all three in the AND feature set, so the merged output
13+
/// must show BTI only. PAC and GCS are present in subsets and should not appear.
14+
15+
// NOTE: Displaying notes found in: .note.gnu.property
16+
// NOTE-NEXT: Owner Data size Description
17+
// NOTE-NEXT: GNU 0x00000028 NT_GNU_PROPERTY_TYPE_0 (property note)
18+
// NOTE-NEXT: Properties: aarch64 feature: BTI
19+
// NOTE-NEXT: AArch64 PAuth ABI core info: platform 0x31 (unknown), version 0x13
20+
21+
// CHECK: .note.gnu.property
1622
// CHECK-NOT: .ARM.attributes
1723

24+
.aeabi_subsection aeabi_pauthabi, required, uleb128
25+
.aeabi_attribute Tag_PAuth_Platform, 49
26+
.aeabi_attribute Tag_PAuth_Schema, 19
1827
.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
1928
.aeabi_attribute Tag_Feature_BTI, 1
2029
.aeabi_attribute Tag_Feature_PAC, 1
2130
.aeabi_attribute Tag_Feature_GCS, 1
2231

23-
.global _start
24-
.type _start, %function
25-
_start:
26-
ret
32+
33+
//--- pauth-bti-gcs.s
34+
.aeabi_subsection aeabi_pauthabi, required, uleb128
35+
.aeabi_attribute Tag_PAuth_Platform, 49
36+
.aeabi_attribute Tag_PAuth_Schema, 19
37+
.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
38+
.aeabi_attribute Tag_Feature_BTI, 1
39+
.aeabi_attribute Tag_Feature_PAC, 0
40+
.aeabi_attribute Tag_Feature_GCS, 1
41+
42+
43+
//--- pauth-bti-pac.s
44+
.aeabi_subsection aeabi_pauthabi, required, uleb128
45+
.aeabi_attribute Tag_PAuth_Platform, 49
46+
.aeabi_attribute Tag_PAuth_Schema, 19
47+
.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
48+
.aeabi_attribute Tag_Feature_BTI, 1
49+
.aeabi_attribute Tag_Feature_PAC, 1
50+
.aeabi_attribute Tag_Feature_GCS, 0

llvm/include/llvm/Support/AArch64AttributeParser.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ class AArch64AttributeParser : public ELFExtendedAttrParser {
2525
: ELFExtendedAttrParser(nullptr, returnTagsNamesMap()) {}
2626
};
2727

28+
// Used for extracting AArch64 Build Attributes
29+
struct AArch64BuildAttrSubsections {
30+
struct PauthSubSection {
31+
uint64_t TagPlatform = 0;
32+
uint64_t TagSchema = 0;
33+
} Pauth;
34+
uint32_t AndFeatures = 0;
35+
};
36+
37+
AArch64BuildAttrSubsections
38+
extractBuildAttributesSubsections(const llvm::AArch64AttributeParser &);
2839
} // namespace llvm
2940

3041
#endif // LLVM_SUPPORT_AARCH64ATTRIBUTEPARSER_H

0 commit comments

Comments
 (0)