From 6182b040eeb66e2f413c7ae31bd895e3fbd02b71 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Wed, 13 Mar 2024 23:07:49 +0300 Subject: [PATCH 1/5] [AArch64][PAC][MC][ELF] Support PAuth ABI compatibility tag Emit `GNU_PROPERTY_AARCH64_FEATURE_PAUTH` property in `.note.gnu.property` section depending on `aarch64-elf-pauthabi-platform` and `aarch64-elf-pauthabi-version` llvm module flags. --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 17 +++++-- .../MCTargetDesc/AArch64TargetStreamer.cpp | 33 +++++++++--- .../MCTargetDesc/AArch64TargetStreamer.h | 3 +- .../AArch64/note-gnu-property-elf-pauthabi.ll | 50 +++++++++++++++++++ 4 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 4fa719ad67cf3..6f7d1548d09c7 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -268,13 +268,24 @@ void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) { if (Sign->getZExtValue()) Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_PAC; - if (Flags == 0) - return; + uint64_t PAuthABIPlatform = -1; + if (const auto *PAP = mdconst::extract_or_null( + M.getModuleFlag("aarch64-elf-pauthabi-platform"))) + PAuthABIPlatform = PAP->getZExtValue(); + uint64_t PAuthABIVersion = -1; + if (const auto *PAV = mdconst::extract_or_null( + M.getModuleFlag("aarch64-elf-pauthabi-version"))) + PAuthABIVersion = PAV->getZExtValue(); + + if ((PAuthABIPlatform == uint64_t(-1)) != (PAuthABIVersion == uint64_t(-1))) + report_fatal_error( + "either both or no 'aarch64-elf-pauthabi-platform' and " + "'aarch64-elf-pauthabi-version' module flags must be present"); // Emit a .note.gnu.property section with the flags. auto *TS = static_cast(OutStreamer->getTargetStreamer()); - TS->emitNoteSection(Flags); + TS->emitNoteSection(Flags, PAuthABIPlatform, PAuthABIVersion); } void AArch64AsmPrinter::emitFunctionHeaderComment() { diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp index e1d6dd7a056bc..dc5383ce941ed 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp @@ -58,8 +58,17 @@ void AArch64TargetStreamer::finish() { emitNoteSection(ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI); } -void AArch64TargetStreamer::emitNoteSection(unsigned Flags) { - if (Flags == 0) +void AArch64TargetStreamer::emitNoteSection(unsigned Flags, + uint64_t PAuthABIPlatform, + uint64_t PAuthABIVersion) { + assert((PAuthABIPlatform == uint64_t(-1)) == + (PAuthABIVersion == uint64_t(-1))); + uint64_t DescSz = 0; + if (Flags != 0) + DescSz += 4 * 4; + if (PAuthABIPlatform != uint64_t(-1)) + DescSz += 4 + 4 + 8 * 2; + if (DescSz == 0) return; MCStreamer &OutStreamer = getStreamer(); @@ -80,15 +89,25 @@ void AArch64TargetStreamer::emitNoteSection(unsigned Flags) { // Emit the note header. OutStreamer.emitValueToAlignment(Align(8)); OutStreamer.emitIntValue(4, 4); // data size for "GNU\0" - OutStreamer.emitIntValue(4 * 4, 4); // Elf_Prop size + OutStreamer.emitIntValue(DescSz, 4); // Elf_Prop array size OutStreamer.emitIntValue(ELF::NT_GNU_PROPERTY_TYPE_0, 4); OutStreamer.emitBytes(StringRef("GNU", 4)); // note name // Emit the PAC/BTI properties. - OutStreamer.emitIntValue(ELF::GNU_PROPERTY_AARCH64_FEATURE_1_AND, 4); - OutStreamer.emitIntValue(4, 4); // data size - OutStreamer.emitIntValue(Flags, 4); // data - OutStreamer.emitIntValue(0, 4); // pad + if (Flags != 0) { + OutStreamer.emitIntValue(ELF::GNU_PROPERTY_AARCH64_FEATURE_1_AND, 4); + OutStreamer.emitIntValue(4, 4); // data size + OutStreamer.emitIntValue(Flags, 4); // data + OutStreamer.emitIntValue(0, 4); // pad + } + + // Emit the PAuth ABI compatibility info + if (PAuthABIPlatform != uint64_t(-1)) { + OutStreamer.emitIntValue(ELF::GNU_PROPERTY_AARCH64_FEATURE_PAUTH, 4); + OutStreamer.emitIntValue(8 * 2, 4); // data size + OutStreamer.emitIntValue(PAuthABIPlatform, 8); + OutStreamer.emitIntValue(PAuthABIVersion, 8); + } OutStreamer.endSection(Nt); OutStreamer.switchSection(Cur); diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h index 7676d88a82b5c..e8a9dc445b96b 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h @@ -35,7 +35,8 @@ class AArch64TargetStreamer : public MCTargetStreamer { void emitCurrentConstantPool(); /// Callback used to implement the .note.gnu.property section. - void emitNoteSection(unsigned Flags); + void emitNoteSection(unsigned Flags, uint64_t PAuthABIPlatform = -1, + uint64_t PAuthABIVersion = -1); /// Callback used to implement the .inst directive. virtual void emitInst(uint32_t Inst); diff --git a/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll b/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll new file mode 100644 index 0000000000000..1eb6a2c7aceac --- /dev/null +++ b/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll @@ -0,0 +1,50 @@ +; RUN: rm -rf %t && split-file %s %t && cd %t + +;--- ok.ll + +; RUN: llc -mtriple=aarch64-linux ok.ll -o - | \ +; RUN: FileCheck %s --check-prefix=ASM +; RUN: llc -mtriple=aarch64-linux ok.ll -filetype=obj -o - | \ +; RUN: llvm-readelf --notes - | FileCheck %s --check-prefix=OBJ + +!llvm.module.flags = !{!0, !1} + +!0 = !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +!1 = !{i32 1, !"aarch64-elf-pauthabi-version", i32 85} + +; ASM: .section .note.gnu.property,"a",@note +; ASM-NEXT: .p2align 3, 0x0 +; ASM-NEXT: .word 4 +; ASM-NEXT: .word 24 +; ASM-NEXT: .word 5 +; ASM-NEXT: .asciz "GNU" +; 3221225473 = 0xc0000001 = GNU_PROPERTY_AARCH64_FEATURE_PAUTH +; ASM-NEXT: .word 3221225473 +; ASM-NEXT: .word 16 +; ASM-NEXT: .xword 268435458 +; ASM-NEXT: .xword 85 + +; OBJ: Displaying notes found in: .note.gnu.property +; OBJ-NEXT: Owner Data size Description +; OBJ-NEXT: GNU 0x00000018 NT_GNU_PROPERTY_TYPE_0 (property note) +; OBJ-NEXT: AArch64 PAuth ABI tag: platform 0x10000002 (llvm_linux), version 0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini) + +; ERR: either both or no 'aarch64-elf-pauthabi-platform' and 'aarch64-elf-pauthabi-version' module flags must be present + +;--- err1.ll + +; RUN: not --crash llc -mtriple=aarch64-linux err1.ll 2>&1 -o - | \ +; RUN: FileCheck %s --check-prefix=ERR + +!llvm.module.flags = !{!0} + +!0 = !{i32 1, !"aarch64-elf-pauthabi-platform", i32 2} + +;--- err2.ll + +; RUN: not --crash llc -mtriple=aarch64-linux err2.ll 2>&1 -o - | \ +; RUN: FileCheck %s --check-prefix=ERR + +!llvm.module.flags = !{!0} + +!0 = !{i32 1, !"aarch64-elf-pauthabi-version", i32 31} From 6a0bec4d09fca0acf1452cfc8e6522f4c4b8cf94 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Wed, 20 Mar 2024 11:14:43 +0300 Subject: [PATCH 2/5] Rename PAuth ABI tag to PAuth ABI core info (see #85231) --- llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll b/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll index 1eb6a2c7aceac..46c4bb1490375 100644 --- a/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll +++ b/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll @@ -27,7 +27,7 @@ ; OBJ: Displaying notes found in: .note.gnu.property ; OBJ-NEXT: Owner Data size Description ; OBJ-NEXT: GNU 0x00000018 NT_GNU_PROPERTY_TYPE_0 (property note) -; OBJ-NEXT: AArch64 PAuth ABI tag: platform 0x10000002 (llvm_linux), version 0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini) +; OBJ-NEXT: AArch64 PAuth ABI core info: platform 0x10000002 (llvm_linux), version 0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini) ; ERR: either both or no 'aarch64-elf-pauthabi-platform' and 'aarch64-elf-pauthabi-version' module flags must be present From ab89fdcb49f9ae6dd2d20cac81cca5204eda51a6 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Wed, 20 Mar 2024 11:16:20 +0300 Subject: [PATCH 3/5] Move check of module flags to verifier --- llvm/lib/IR/Verifier.cpp | 23 ++++++++++++++++++- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 5 ---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index a923f5e2a34e7..85de16e65c172 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1734,8 +1734,29 @@ void Verifier::visitModuleFlags() { // Scan each flag, and track the flags and requirements. DenseMap SeenIDs; SmallVector Requirements; - for (const MDNode *MDN : Flags->operands()) + uint64_t PAuthABIPlatform = -1; + uint64_t PAuthABIVersion = -1; + for (const MDNode *MDN : Flags->operands()) { visitModuleFlag(MDN, SeenIDs, Requirements); + if (MDN->getNumOperands() != 3) + continue; + if (const auto *FlagName = dyn_cast_or_null(MDN->getOperand(1))) { + if (FlagName->getString() == "aarch64-elf-pauthabi-platform") { + if (const auto *PAP = + mdconst::dyn_extract_or_null(MDN->getOperand(2))) + PAuthABIPlatform = PAP->getZExtValue(); + } else if (FlagName->getString() == "aarch64-elf-pauthabi-version") { + if (const auto *PAV = + mdconst::dyn_extract_or_null(MDN->getOperand(2))) + PAuthABIVersion = PAV->getZExtValue(); + } + } + } + + if ((PAuthABIPlatform == uint64_t(-1)) != (PAuthABIVersion == uint64_t(-1))) + report_fatal_error( + "either both or no 'aarch64-elf-pauthabi-platform' and " + "'aarch64-elf-pauthabi-version' module flags must be present"); // Validate that the requirements in the module are valid. for (const MDNode *Requirement : Requirements) { diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 6f7d1548d09c7..f6ccd0ecfdc89 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -277,11 +277,6 @@ void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) { M.getModuleFlag("aarch64-elf-pauthabi-version"))) PAuthABIVersion = PAV->getZExtValue(); - if ((PAuthABIPlatform == uint64_t(-1)) != (PAuthABIVersion == uint64_t(-1))) - report_fatal_error( - "either both or no 'aarch64-elf-pauthabi-platform' and " - "'aarch64-elf-pauthabi-version' module flags must be present"); - // Emit a .note.gnu.property section with the flags. auto *TS = static_cast(OutStreamer->getTargetStreamer()); From 2f6dc0adbee9e09176e86dd9960b8d353c31decf Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Fri, 22 Mar 2024 10:18:51 +0300 Subject: [PATCH 4/5] Address review comments - Use `CheckFailed` instead of `report_fatal_error` in verifier - Add tests for verifier --- llvm/lib/IR/Verifier.cpp | 2 +- .../AArch64/note-gnu-property-elf-pauthabi.ll | 4 ++-- ...le-flags-note-gnu-property-elf-pauthabi.ll | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 llvm/test/Verifier/module-flags-note-gnu-property-elf-pauthabi.ll diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 85de16e65c172..f5fd429b99988 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1754,7 +1754,7 @@ void Verifier::visitModuleFlags() { } if ((PAuthABIPlatform == uint64_t(-1)) != (PAuthABIVersion == uint64_t(-1))) - report_fatal_error( + CheckFailed( "either both or no 'aarch64-elf-pauthabi-platform' and " "'aarch64-elf-pauthabi-version' module flags must be present"); diff --git a/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll b/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll index 46c4bb1490375..728cffeba02a2 100644 --- a/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll +++ b/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll @@ -33,7 +33,7 @@ ;--- err1.ll -; RUN: not --crash llc -mtriple=aarch64-linux err1.ll 2>&1 -o - | \ +; RUN: not llc -mtriple=aarch64-linux err1.ll 2>&1 -o - | \ ; RUN: FileCheck %s --check-prefix=ERR !llvm.module.flags = !{!0} @@ -42,7 +42,7 @@ ;--- err2.ll -; RUN: not --crash llc -mtriple=aarch64-linux err2.ll 2>&1 -o - | \ +; RUN: not llc -mtriple=aarch64-linux err2.ll 2>&1 -o - | \ ; RUN: FileCheck %s --check-prefix=ERR !llvm.module.flags = !{!0} diff --git a/llvm/test/Verifier/module-flags-note-gnu-property-elf-pauthabi.ll b/llvm/test/Verifier/module-flags-note-gnu-property-elf-pauthabi.ll new file mode 100644 index 0000000000000..435073d01c8e6 --- /dev/null +++ b/llvm/test/Verifier/module-flags-note-gnu-property-elf-pauthabi.ll @@ -0,0 +1,19 @@ +; RUN: rm -rf %t && split-file %s %t && cd %t + +; CHECK: either both or no 'aarch64-elf-pauthabi-platform' and 'aarch64-elf-pauthabi-version' module flags must be present + +;--- err1.ll + +; RUN: not llvm-as err1.ll -o /dev/null 2>&1 | FileCheck %s + +!llvm.module.flags = !{!0} + +!0 = !{i32 1, !"aarch64-elf-pauthabi-platform", i32 2} + +;--- err2.ll + +; RUN: not llvm-as err2.ll -o /dev/null 2>&1 | FileCheck %s + +!llvm.module.flags = !{!0} + +!0 = !{i32 1, !"aarch64-elf-pauthabi-version", i32 31} From d313921f61139c630652a798afce1ea0a0f438c5 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Fri, 22 Mar 2024 10:57:44 +0300 Subject: [PATCH 5/5] Fix code formatting --- llvm/lib/IR/Verifier.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index f5fd429b99988..3ae812cfa2501 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1754,9 +1754,8 @@ void Verifier::visitModuleFlags() { } if ((PAuthABIPlatform == uint64_t(-1)) != (PAuthABIVersion == uint64_t(-1))) - CheckFailed( - "either both or no 'aarch64-elf-pauthabi-platform' and " - "'aarch64-elf-pauthabi-version' module flags must be present"); + CheckFailed("either both or no 'aarch64-elf-pauthabi-platform' and " + "'aarch64-elf-pauthabi-version' module flags must be present"); // Validate that the requirements in the module are valid. for (const MDNode *Requirement : Requirements) {