Skip to content

[lld][AArch64][Build Attributes] Add support for AArch64 Build Attributes #144082

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 79 additions & 6 deletions lld/ELF/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Object/IRObjectFile.h"
#include "llvm/Support/AArch64AttributeParser.h"
#include "llvm/Support/ARMAttributeParser.h"
#include "llvm/Support/ARMBuildAttributes.h"
#include "llvm/Support/Endian.h"
Expand Down Expand Up @@ -537,6 +538,46 @@ uint32_t ObjFile<ELFT>::getSectionIndex(const Elf_Sym &sym) const {
this);
}

template <class ELFT>
static void
handleAArch64BAAndGnuProperties(ObjFile<ELFT> *file, Ctx &ctx,
const AArch64BuildAttrSubsections &baInfo) {
if (file->aarch64PauthAbiCoreInfo) {
// Check for data mismatch
if (file->aarch64PauthAbiCoreInfo) {
if (baInfo.Pauth.TagPlatform != file->aarch64PauthAbiCoreInfo->platform ||
baInfo.Pauth.TagSchema != file->aarch64PauthAbiCoreInfo->version)
Err(ctx)
<< file
<< " Pauth Data mismatch: file contains both GNU properties and "
"AArch64 build attributes sections with different Pauth data";
}
if (baInfo.AndFeatures != file->andFeatures)
Err(ctx) << file
<< " Features Data mismatch: file contains both GNU "
"properties and AArch64 build attributes sections with "
"different And Features data";
} else {
// When BuildAttributes are missing, PauthABI value defaults to (TagPlatform
// = 0, TagSchema = 0). GNU properties do not write PAuthAbiCoreInfo if GNU
// property is not present. To match this behaviour, we only write
// PAuthAbiCoreInfo when there is at least one non-zero value. The
// specification reserves TagPlatform = 0, TagSchema = 1 values to match the
// 'Invalid' GNU property section with platform = 0, version = 0.
if (baInfo.Pauth.TagPlatform || baInfo.Pauth.TagSchema) {
if (baInfo.Pauth.TagPlatform == 0 && baInfo.Pauth.TagSchema == 1)
file->aarch64PauthAbiCoreInfo = {0, 0};
else
file->aarch64PauthAbiCoreInfo = {baInfo.Pauth.TagPlatform,
baInfo.Pauth.TagSchema};
}
file->andFeatures = baInfo.AndFeatures;
}
}

template <typename ELFT>
static void readGnuProperty(Ctx &, const InputSection &, ObjFile<ELFT> &);

template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
object::ELFFile<ELFT> obj = this->getObj();
// Read a section table. justSymbols is usually false.
Expand All @@ -552,8 +593,23 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
StringRef shstrtab = CHECK2(obj.getSectionStringTable(objSections), this);
uint64_t size = objSections.size();
sections.resize(size);

AArch64BuildAttrSubsections aarch64BAsubSections;
bool hasAArch64BuildAttributes = false;

for (size_t i = 0; i != size; ++i) {
const Elf_Shdr &sec = objSections[i];
// Read GNU property section into a per-InputFile structure that will be
// merged at a later stage. A synthetic section will be created for the
// merged contents.
if (check(obj.getSectionName(sec, shstrtab)) == ".note.gnu.property") {
readGnuProperty(
ctx,
InputSection(*this, sec, check(obj.getSectionName(sec, shstrtab))),
*this);
sections[i] = &InputSection::discarded;
}

if (LLVM_LIKELY(sec.sh_type == SHT_PROGBITS))
continue;
if (LLVM_LIKELY(sec.sh_type == SHT_GROUP)) {
Expand Down Expand Up @@ -637,13 +693,23 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
}
break;
case EM_AARCH64:
// FIXME: BuildAttributes have been implemented in llvm, but not yet in
// lld. Remove the section so that it does not accumulate in the output
// file. When support is implemented we expect not to output a build
// attributes section in files of type ET_EXEC or ET_SHARED, but ld -r
// ouptut will need a single merged attributes section.
if (sec.sh_type == SHT_AARCH64_ATTRIBUTES)
// Extract Build Attributes section contents into aarch64BAsubSections.
// Input objects may contain both build Build Attributes and GNU
// properties. We delay processing Build Attributes until we have finished
// reading all sections so that we can check that these are consistent.
if (sec.sh_type == SHT_AARCH64_ATTRIBUTES) {
ArrayRef<uint8_t> contents = check(obj.getSectionContents(sec));
AArch64AttributeParser attributes;
if (Error e = attributes.parse(contents, ELFT::Endianness)) {
StringRef name = check(obj.getSectionName(sec, shstrtab));
InputSection isec(*this, sec, name);
Warn(ctx) << &isec << ": " << std::move(e);
} else {
aarch64BAsubSections = extractBuildAttributesSubsections(attributes);
hasAArch64BuildAttributes = true;
}
sections[i] = &InputSection::discarded;
}
// Producing a static binary with MTE globals is not currently supported,
// remove all SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections as they're unused
// medatada, and we don't want them to end up in the output file for
Expand All @@ -655,6 +721,13 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
}
}

if (hasAArch64BuildAttributes) {
// Handle AArch64 Build Attributes and GNU properties:
// - Err on mismatched values.
// - Store missing values as GNU properties.
handleAArch64BAAndGnuProperties<ELFT>(this, ctx, aarch64BAsubSections);
}

// Read a symbol table.
initializeSymbols(obj);
}
Expand Down
29 changes: 29 additions & 0 deletions lld/test/ELF/aarch64-build-attributes-be.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// REQUIRES: aarch64
// RUN: llvm-mc -triple=aarch64_be %s -filetype=obj -o %t.o
// RUN: ld.lld %t.o --shared -o %t.so
// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE

// RUN: llvm-mc -triple=aarch64_be %s -filetype=obj -o %t.o
// RUN: ld.lld %t.o --shared -o %t.so
// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
// RUN: ld.lld %t.o -o %t
// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
// RUN: ld.lld -r %t.o -o %t2.o
// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE

/// Test that lld can read big-endian build-attributes.

// NOTE: Displaying notes found in: .note.gnu.property
// NOTE-NEXT: Owner Data size Description
// NOTE-NEXT: GNU 0x00000028 NT_GNU_PROPERTY_TYPE_0 (property note)
// NOTE-NEXT: Properties: aarch64 feature: BTI, PAC, GCS
// NOTE-NEXT: AArch64 PAuth ABI core info: platform 0x89abcdef (unknown), version 0x89abcdef


.aeabi_subsection aeabi_pauthabi, required, uleb128
.aeabi_attribute Tag_PAuth_Platform, 0x123456789ABCDEF
.aeabi_attribute Tag_PAuth_Schema, 0x123456789ABCDEF
.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
.aeabi_attribute Tag_Feature_BTI, 1
.aeabi_attribute Tag_Feature_PAC, 1
.aeabi_attribute Tag_Feature_GCS, 1
35 changes: 35 additions & 0 deletions lld/test/ELF/aarch64-build-attributes-err.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// REQUIRES: aarch64

// RUN: llvm-mc -triple=aarch64 %s -filetype=obj -o %t.o
// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR

// ERR: Pauth Data mismatch: file contains both GNU properties and AArch64 build attributes sections with different Pauth data
// ERR-NEXT: Features Data mismatch: file contains both GNU properties and AArch64 build attributes sections with different And Features data

.aeabi_subsection aeabi_pauthabi, required, uleb128
.aeabi_attribute Tag_PAuth_Platform, 5
.aeabi_attribute Tag_PAuth_Schema, 5
.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
.aeabi_attribute Tag_Feature_BTI, 1
.aeabi_attribute Tag_Feature_PAC, 1
.aeabi_attribute Tag_Feature_GCS, 1

.section ".note.gnu.property", "a"
.long 0x4
.long 0x10
.long 0x5
.asciz "GNU"
.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
.long 0x4
.long 0x2 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC
.long 0x0

.section ".note.gnu.property", "a"
.long 0x4
.long 0x18
.long 0x5
.asciz "GNU"
.long 0xc0000001
.long 0x10
.quad 0x12345678 // platform
.quad 0x87654321 // version
18 changes: 18 additions & 0 deletions lld/test/ELF/aarch64-build-attributes-invalid.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// REQUIRES: aarch64

// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t.o
// RUN: ld.lld -r %t.o -o %t.invalid.o
// RUN: llvm-readelf -n %t.invalid.o | FileCheck %s

/// According to the BuildAttributes specification Build Attributes
/// A (TagPlatform, TagSchema)of (0, 1) maps to an explicit PAuth property
/// of platform = 0, version = 0 ('Invalid').

// CHECK: Displaying notes found in: .note.gnu.property
// CHECK-NEXT: Owner Data size Description
// CHECK-NEXT: GNU 0x00000018 NT_GNU_PROPERTY_TYPE_0 (property note)
// CHECK-NEXT: Properties: AArch64 PAuth ABI core info: platform 0x0 (invalid), version 0x0

.aeabi_subsection aeabi_pauthabi, required, uleb128
.aeabi_attribute Tag_PAuth_Platform, 0
.aeabi_attribute Tag_PAuth_Schema, 1
18 changes: 18 additions & 0 deletions lld/test/ELF/aarch64-build-attributes-malformed.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# REQUIRES: aarch64

# RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t.o
# RUN: ld.lld %t.o /dev/null 2>&1 | FileCheck %s

# CHECK: (.ARM.attributes): unexpected end of data at offset 0x3f while reading [0x3d, 0x41)

.section .ARM.attributes,"",%0x70000003
.byte 0x41 // Tag 'A' (format version)
.long 0x00000019 // Subsection length
.asciz "aeabi_pauthabi" // Subsection name
.byte 0x00, 0x00 // Optionality and Type
.byte 0x01, 0x01, 0x02, 0x01 // PAuth_Platform and PAuth_Schema
.long 0x00000023 // Subsection length
.asciz "aeabi_feature_and_bits" // Subsection name
.byte 0x01, 0x00 // Optionality and Type
.byte 0x00, 0x01, 0x01, 0x01, 0x02, 0x01 // BTI, PAC, GCS
.byte 0x00, 0x00 // This is the malformation, data is too long.
67 changes: 67 additions & 0 deletions lld/test/ELF/aarch64-build-attributes-mixed.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// REQUIRES: aarch64

// RUN: rm -rf %t && split-file %s %t && cd %t

// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t11.o
// RUN: llvm-mc -triple=aarch64 -filetype=obj merged-property.s -o %t12.o
// RUN: llvm-mc -triple=aarch64 -filetype=obj merged-property2.s -o %t13.o
// RUN: ld.lld -r %t11.o %t12.o %t13.o -o %t.merged1.o
// RUN: llvm-readelf -n %t.merged1.o | FileCheck %s --check-prefix=NOTE-MIXED

/// This test verifies merging of AArch64 build attributes and GNU property notes.
/// Three object files are combined: one with build attributes (PAuth information, BTI, PAC, GCS),
/// and two with GNU property notes encoding the same feature bits.
/// PAuth ABI info is provided in one of the files and it is expected to be preserved in the merged output.

// NOTE-MIXED: Displaying notes found in: .note.gnu.property
// NOTE-MIXED-NEXT: Owner Data size Description
// NOTE-MIXED-NEXT: GNU 0x00000028 NT_GNU_PROPERTY_TYPE_0 (property note)
// NOTE-MIXED-NEXT: Properties: aarch64 feature: BTI, PAC
// NOTE-MIXED-NEXT: AArch64 PAuth ABI core info: platform 0x31 (unknown), version 0x13

// CHECK: .note.gnu.property
// CHECK-NOT: .ARM.attributes

.aeabi_subsection aeabi_pauthabi, required, uleb128
.aeabi_attribute Tag_PAuth_Platform, 49
.aeabi_attribute Tag_PAuth_Schema, 19
.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
.aeabi_attribute Tag_Feature_BTI, 1
.aeabi_attribute Tag_Feature_PAC, 1
.aeabi_attribute Tag_Feature_GCS, 1


//--- merged-property.s
.section ".note.gnu.property", "a"
.long 0x4 // Name length is always 4 ("GNU")
.long end - begin // Data length
.long 0x5 // Type: NT_GNU_PROPERTY_TYPE_0
.asciz "GNU" // Name
.p2align 0x3
begin:
.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
.long 0x4
.long 0x7 // pr_data: BTI (1), PAC (2), GCS (4) = 0b111 = 7
.long 0x0
// PAuth ABI property note
.long 0xc0000001 // GNU_PROPERTY_AARCH64_FEATURE_PAUTH
.long 0x10 // Data length
.quad 0x31 // PAuth ABI platform
.quad 0x13 // PAuth ABI version
.p2align 0x3 // Align to 8 byte for 64 bit
end:

//--- merged-property2.s
.section .note.gnu.property, "a"
.align 0x4
.long 0x4 // Name length is always 4 ("GNU")
.long end2 - begin2 // Data length
.long 0x5 // Type: NT_GNU_PROPERTY_TYPE_0
.asciz "GNU" // Name
begin2:
.align 0x4
.long 0xc0000000 // Type: GNU_PROPERTY_AARCH64_FEATURE_1_AND
.long 0x4 // Data length
.long 0x7 // pr_data: BTI (1), PAC (2), GCS (4) = 0b111 = 7
.long 0x0
end2:
58 changes: 41 additions & 17 deletions lld/test/ELF/aarch64-build-attributes.s
Original file line number Diff line number Diff line change
@@ -1,26 +1,50 @@
// REQUIRES: aarch64
// RUN: llvm-mc -triple=aarch64 %s -filetype=obj -o %t.o
// RUN: ld.lld %t.o --shared -o %t.so
// RUN: llvm-readelf --sections %t.so | FileCheck %s
// RUN: ld.lld %t.o -o %t
// RUN: llvm-readelf --sections %t | FileCheck %s
// RUN: ld.lld -r %t.o -o %t2.o
// RUN: llvm-readelf --sections %t2.o | FileCheck %s

/// File has a Build attributes section. This should not appear in
/// ET_EXEC or ET_SHARED files as there is no requirement for it to
/// do so. FIXME, the ld -r (relocatable link) should output a single
/// merged build attributes section. When full support is added in
/// ld.lld this test should be updated.
// RUN: rm -rf %t && split-file %s %t && cd %t

// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t1.o
// RUN: llvm-mc -triple=aarch64 -filetype=obj pauth-bti-gcs.s -o %t2.o
// RUN: llvm-mc -triple=aarch64 -filetype=obj pauth-bti-pac.s -o %t3.o
// RUN: ld.lld -r %t1.o %t2.o %t3.o -o %t.merged.o
// RUN: llvm-readelf -n %t.merged.o | FileCheck %s --check-prefix=NOTE

/// This test merges three object files with AArch64 build attributes.
/// All contain identical PAuth ABI info (platform/version), which must be preserved.
/// Only BTI is common across all three in the AND feature set, so the merged output
/// must show BTI only. PAC and GCS are present in subsets and should not appear.

// NOTE: Displaying notes found in: .note.gnu.property
// NOTE-NEXT: Owner Data size Description
// NOTE-NEXT: GNU 0x00000028 NT_GNU_PROPERTY_TYPE_0 (property note)
// NOTE-NEXT: Properties: aarch64 feature: BTI
// NOTE-NEXT: AArch64 PAuth ABI core info: platform 0x31 (unknown), version 0x13

// CHECK: .note.gnu.property
// CHECK-NOT: .ARM.attributes

.aeabi_subsection aeabi_pauthabi, required, uleb128
.aeabi_attribute Tag_PAuth_Platform, 49
.aeabi_attribute Tag_PAuth_Schema, 19
.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
.aeabi_attribute Tag_Feature_BTI, 1
.aeabi_attribute Tag_Feature_PAC, 1
.aeabi_attribute Tag_Feature_GCS, 1

.global _start
.type _start, %function
_start:
ret

//--- pauth-bti-gcs.s
.aeabi_subsection aeabi_pauthabi, required, uleb128
.aeabi_attribute Tag_PAuth_Platform, 49
.aeabi_attribute Tag_PAuth_Schema, 19
.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
.aeabi_attribute Tag_Feature_BTI, 1
.aeabi_attribute Tag_Feature_PAC, 0
.aeabi_attribute Tag_Feature_GCS, 1


//--- pauth-bti-pac.s
.aeabi_subsection aeabi_pauthabi, required, uleb128
.aeabi_attribute Tag_PAuth_Platform, 49
.aeabi_attribute Tag_PAuth_Schema, 19
.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
.aeabi_attribute Tag_Feature_BTI, 1
.aeabi_attribute Tag_Feature_PAC, 1
.aeabi_attribute Tag_Feature_GCS, 0
11 changes: 11 additions & 0 deletions llvm/include/llvm/Support/AArch64AttributeParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ class AArch64AttributeParser : public ELFExtendedAttrParser {
: ELFExtendedAttrParser(nullptr, returnTagsNamesMap()) {}
};

// Used for extracting AArch64 Build Attributes
struct AArch64BuildAttrSubsections {
struct PauthSubSection {
uint64_t TagPlatform = 0;
uint64_t TagSchema = 0;
} Pauth;
uint32_t AndFeatures = 0;
};

AArch64BuildAttrSubsections
extractBuildAttributesSubsections(const llvm::AArch64AttributeParser &);
} // namespace llvm

#endif // LLVM_SUPPORT_AARCH64ATTRIBUTEPARSER_H
Loading