[clang] [llvm] [PAC][ELF][AArch64] Support signed personality function pointer (PR #113148)

Daniil Kovalev via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 18 05:20:54 PST 2024


https://github.com/kovdan01 updated https://github.com/llvm/llvm-project/pull/113148

>From e192b193471831d004a715ce3b1684198342dba4 Mon Sep 17 00:00:00 2001
From: Daniil Kovalev <dkovalev at accesssoftek.com>
Date: Mon, 21 Oct 2024 13:28:58 +0300
Subject: [PATCH] [PAC][ELF][AArch64] Support signed personality function
 pointer

If function pointer signing is enabled, sign personality function pointer
stored in `.DW.ref.__gxx_personality_v0` section with IA key,
0x7EAD = `ptrauth_string_discriminator("personality")` constant discriminator
and address diversity enabled.
---
 clang/lib/CodeGen/CodeGenModule.cpp           |  3 ++
 clang/test/CodeGen/ptrauth-module-flags.c     |  8 ++++
 .../llvm/CodeGen/MachineModuleInfoImpls.h     |  8 +++-
 .../CodeGen/TargetLoweringObjectFileImpl.h    |  8 +++-
 .../llvm/Target/TargetLoweringObjectFile.h    |  3 +-
 .../CodeGen/AsmPrinter/DwarfCFIException.cpp  |  3 +-
 llvm/lib/CodeGen/MachineModuleInfoImpls.cpp   | 12 ++++++
 .../CodeGen/TargetLoweringObjectFileImpl.cpp  | 10 ++++-
 .../AArch64/AArch64TargetObjectFile.cpp       | 16 ++++++++
 .../Target/AArch64/AArch64TargetObjectFile.h  |  4 ++
 .../MCTargetDesc/AArch64TargetStreamer.cpp    | 10 +++++
 .../MCTargetDesc/AArch64TargetStreamer.h      |  7 ++++
 llvm/lib/Target/TargetLoweringObjectFile.cpp  |  7 ++--
 .../AArch64/ptrauth-sign-personality.ll       | 39 +++++++++++++++++++
 14 files changed, 129 insertions(+), 9 deletions(-)
 create mode 100644 clang/test/CodeGen/ptrauth-module-flags.c
 create mode 100644 llvm/test/CodeGen/AArch64/ptrauth-sign-personality.ll

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 508f53482d4e1f..8b2d92a6cc9379 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1214,6 +1214,9 @@ void CodeGenModule::Release() {
                                 "sign-return-address-with-bkey", 1);
 
     if (getTriple().isOSLinux()) {
+      if (LangOpts.PointerAuthCalls)
+        getModule().addModuleFlag(llvm::Module::Min, "ptrauth-sign-personality",
+                                  1);
       assert(getTriple().isOSBinFormatELF());
       using namespace llvm::ELF;
       uint64_t PAuthABIVersion =
diff --git a/clang/test/CodeGen/ptrauth-module-flags.c b/clang/test/CodeGen/ptrauth-module-flags.c
new file mode 100644
index 00000000000000..150e5bf59fb05e
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-module-flags.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple aarch64-linux-gnu                   -emit-llvm %s  -o - | FileCheck %s --check-prefix=OFF
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls   -emit-llvm %s  -o - | FileCheck %s --check-prefix=PERSONALITY
+
+// PERSONALITY:      !llvm.module.flags = !{
+// PERSONALITY-SAME: !1
+// PERSONALITY:      !1 = !{i32 8, !"ptrauth-sign-personality", i32 1}
+
+// OFF-NOT: "ptrauth-
diff --git a/llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h b/llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h
index c1ae3d2d966df5..f7a028625ee3c8 100644
--- a/llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h
+++ b/llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h
@@ -83,10 +83,14 @@ class MachineModuleInfoELF : public MachineModuleInfoImpl {
   /// extern_weak symbols.
   DenseMap<MCSymbol *, const MCExpr *> AuthPtrStubs;
 
+  /// HasSignedPersonality is true if the corresponding IR module has the
+  /// "ptrauth-sign-personality" flag set to 1.
+  bool HasSignedPersonality = false;
+
   virtual void anchor(); // Out of line virtual method.
 
 public:
-  MachineModuleInfoELF(const MachineModuleInfo &) {}
+  MachineModuleInfoELF(const MachineModuleInfo &);
 
   StubValueTy &getGVStubEntry(MCSymbol *Sym) {
     assert(Sym && "Key cannot be null");
@@ -105,6 +109,8 @@ class MachineModuleInfoELF : public MachineModuleInfoImpl {
   ExprStubListTy getAuthGVStubList() {
     return getSortedExprStubs(AuthPtrStubs);
   }
+
+  bool hasSignedPersonality() const { return HasSignedPersonality; }
 };
 
 /// MachineModuleInfoCOFF - This is a MachineModuleInfoImpl implementation
diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
index 8eef45ce565deb..a2a9e5d499e527 100644
--- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
+++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
@@ -52,7 +52,13 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile {
   void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override;
 
   void emitPersonalityValue(MCStreamer &Streamer, const DataLayout &DL,
-                            const MCSymbol *Sym) const override;
+                            const MCSymbol *Sym,
+                            const MachineModuleInfo *MMI) const override;
+
+  virtual void emitPersonalityValueImpl(MCStreamer &Streamer,
+                                        const DataLayout &DL,
+                                        const MCSymbol *Sym,
+                                        const MachineModuleInfo *MMI) const;
 
   /// Given a constant with the SectionKind, return a section that it should be
   /// placed in.
diff --git a/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/llvm/include/llvm/Target/TargetLoweringObjectFile.h
index 0c09cfe684783b..4864ba843f4886 100644
--- a/llvm/include/llvm/Target/TargetLoweringObjectFile.h
+++ b/llvm/include/llvm/Target/TargetLoweringObjectFile.h
@@ -82,7 +82,8 @@ class TargetLoweringObjectFile : public MCObjectFileInfo {
   virtual void Initialize(MCContext &ctx, const TargetMachine &TM);
 
   virtual void emitPersonalityValue(MCStreamer &Streamer, const DataLayout &TM,
-                                    const MCSymbol *Sym) const;
+                                    const MCSymbol *Sym,
+                                    const MachineModuleInfo *MMI) const;
 
   /// Emit the module-level metadata that the platform cares about.
   virtual void emitModuleMetadata(MCStreamer &Streamer, Module &M) const {}
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp
index 087ee02a7f2b35..4fac4bbc98477d 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp
@@ -50,7 +50,8 @@ void DwarfCFIException::endModule() {
   // Emit indirect reference table for all used personality functions
   for (const GlobalValue *Personality : Personalities) {
     MCSymbol *Sym = Asm->getSymbol(Personality);
-    TLOF.emitPersonalityValue(*Asm->OutStreamer, Asm->getDataLayout(), Sym);
+    TLOF.emitPersonalityValue(*Asm->OutStreamer, Asm->getDataLayout(), Sym,
+                              Asm->MMI);
   }
   Personalities.clear();
 }
diff --git a/llvm/lib/CodeGen/MachineModuleInfoImpls.cpp b/llvm/lib/CodeGen/MachineModuleInfoImpls.cpp
index 956317510dc736..0d8c30883d6dcf 100644
--- a/llvm/lib/CodeGen/MachineModuleInfoImpls.cpp
+++ b/llvm/lib/CodeGen/MachineModuleInfoImpls.cpp
@@ -14,6 +14,8 @@
 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Module.h"
 #include "llvm/MC/MCSymbol.h"
 
 using namespace llvm;
@@ -59,3 +61,13 @@ MachineModuleInfoImpl::ExprStubListTy MachineModuleInfoImpl::getSortedExprStubs(
   ExprStubs.clear();
   return List;
 }
+
+MachineModuleInfoELF::MachineModuleInfoELF(const MachineModuleInfo &MMI) {
+  const Module *M = MMI.getModule();
+  const auto *Flag = mdconst::extract_or_null<ConstantInt>(
+      M->getModuleFlag("ptrauth-sign-personality"));
+  if (Flag && Flag->getZExtValue() == 1)
+    HasSignedPersonality = true;
+  else
+    HasSignedPersonality = false;
+}
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index ce50a3c19ffe04..d5342b5d3651f1 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -413,7 +413,8 @@ MCSymbol *TargetLoweringObjectFileELF::getCFIPersonalitySymbol(
 }
 
 void TargetLoweringObjectFileELF::emitPersonalityValue(
-    MCStreamer &Streamer, const DataLayout &DL, const MCSymbol *Sym) const {
+    MCStreamer &Streamer, const DataLayout &DL, const MCSymbol *Sym,
+    const MachineModuleInfo *MMI) const {
   SmallString<64> NameData("DW.ref.");
   NameData += Sym->getName();
   MCSymbolELF *Label =
@@ -431,6 +432,13 @@ void TargetLoweringObjectFileELF::emitPersonalityValue(
   Streamer.emitELFSize(Label, E);
   Streamer.emitLabel(Label);
 
+  emitPersonalityValueImpl(Streamer, DL, Sym, MMI);
+}
+
+void TargetLoweringObjectFileELF::emitPersonalityValueImpl(
+    MCStreamer &Streamer, const DataLayout &DL, const MCSymbol *Sym,
+    const MachineModuleInfo *MMI) const {
+  unsigned Size = DL.getPointerSize();
   Streamer.emitSymbolValue(Sym, Size);
 }
 
diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
index 54de42a094f340..9b242f3213d01f 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
@@ -9,6 +9,7 @@
 #include "AArch64TargetObjectFile.h"
 #include "AArch64TargetMachine.h"
 #include "MCTargetDesc/AArch64MCExpr.h"
+#include "MCTargetDesc/AArch64TargetStreamer.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
 #include "llvm/IR/Mangler.h"
@@ -28,6 +29,21 @@ void AArch64_ELFTargetObjectFile::Initialize(MCContext &Ctx,
   SupportDebugThreadLocalLocation = false;
 }
 
+void AArch64_ELFTargetObjectFile::emitPersonalityValueImpl(
+    MCStreamer &Streamer, const DataLayout &DL, const MCSymbol *Sym,
+    const MachineModuleInfo *MMI) const {
+  if (!MMI->getObjFileInfo<MachineModuleInfoELF>().hasSignedPersonality()) {
+    TargetLoweringObjectFileELF::emitPersonalityValueImpl(Streamer, DL, Sym,
+                                                          MMI);
+    return;
+  }
+  auto *TS = static_cast<AArch64TargetStreamer *>(Streamer.getTargetStreamer());
+  // The value is ptrauth_string_discriminator("personality")
+  constexpr uint16_t Discriminator = 0x7EAD;
+  TS->emitAuthValue(MCSymbolRefExpr::create(Sym, getContext()), Discriminator,
+                    AArch64PACKey::IA, true, getContext());
+}
+
 const MCExpr *AArch64_ELFTargetObjectFile::getIndirectSymViaGOTPCRel(
     const GlobalValue *GV, const MCSymbol *Sym, const MCValue &MV,
     int64_t Offset, MachineModuleInfo *MMI, MCStreamer &Streamer) const {
diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
index 2ef8bda2988d47..0c822ac84f200c 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
+++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
@@ -35,6 +35,10 @@ class AArch64_ELFTargetObjectFile : public TargetLoweringObjectFileELF {
                                  MachineModuleInfo *MMI, const MCSymbol *RawSym,
                                  AArch64PACKey::ID Key,
                                  uint16_t Discriminator) const;
+
+  void emitPersonalityValueImpl(MCStreamer &Streamer, const DataLayout &DL,
+                                const MCSymbol *Sym,
+                                const MachineModuleInfo *MMI) const override;
 };
 
 /// AArch64_MachoTargetObjectFile - This TLOF implementation is used for Darwin.
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
index dc5383ce941ed9..c453cd6f768c3d 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
@@ -35,6 +35,16 @@ AArch64TargetStreamer::AArch64TargetStreamer(MCStreamer &S)
 
 AArch64TargetStreamer::~AArch64TargetStreamer() = default;
 
+void AArch64TargetStreamer::emitAuthValue(const MCExpr *Expr,
+                                          uint16_t Discriminator,
+                                          AArch64PACKey::ID Key,
+                                          bool HasAddressDiversity,
+                                          MCContext &Ctx) {
+  Streamer.emitValueImpl(AArch64AuthMCExpr::create(Expr, Discriminator, Key,
+                                                   HasAddressDiversity, Ctx),
+                         8);
+}
+
 // The constant pool handling is shared by all AArch64TargetStreamer
 // implementations.
 const MCExpr *AArch64TargetStreamer::addConstantPoolEntry(const MCExpr *Expr,
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
index ac441ae3b603ff..e6d448e45d45d3 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64TARGETSTREAMER_H
 #define LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64TARGETSTREAMER_H
 
+#include "AArch64MCExpr.h"
 #include "llvm/MC/MCStreamer.h"
 
 namespace {
@@ -38,6 +39,12 @@ class AArch64TargetStreamer : public MCTargetStreamer {
   void emitNoteSection(unsigned Flags, uint64_t PAuthABIPlatform = -1,
                        uint64_t PAuthABIVersion = -1);
 
+  /// Callback used to emit AUTH expressions (e.g. signed
+  /// personality function pointer).
+  void emitAuthValue(const MCExpr *Expr, uint16_t Discriminator,
+                     AArch64PACKey::ID Key, bool HasAddressDiversity,
+                     MCContext &Ctx);
+
   /// Callback used to implement the .inst directive.
   virtual void emitInst(uint32_t Inst);
 
diff --git a/llvm/lib/Target/TargetLoweringObjectFile.cpp b/llvm/lib/Target/TargetLoweringObjectFile.cpp
index 7d9b926f4c42b6..4fe9d13d062265 100644
--- a/llvm/lib/Target/TargetLoweringObjectFile.cpp
+++ b/llvm/lib/Target/TargetLoweringObjectFile.cpp
@@ -141,10 +141,9 @@ MCSymbol *TargetLoweringObjectFile::getCFIPersonalitySymbol(
   return TM.getSymbol(GV);
 }
 
-void TargetLoweringObjectFile::emitPersonalityValue(MCStreamer &Streamer,
-                                                    const DataLayout &,
-                                                    const MCSymbol *Sym) const {
-}
+void TargetLoweringObjectFile::emitPersonalityValue(
+    MCStreamer &Streamer, const DataLayout &, const MCSymbol *Sym,
+    const MachineModuleInfo *MMI) const {}
 
 void TargetLoweringObjectFile::emitCGProfileMetadata(MCStreamer &Streamer,
                                                      Module &M) const {
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-sign-personality.ll b/llvm/test/CodeGen/AArch64/ptrauth-sign-personality.ll
new file mode 100644
index 00000000000000..d4ee49d9aeeabf
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/ptrauth-sign-personality.ll
@@ -0,0 +1,39 @@
+; RUN: llc -mtriple=aarch64-linux -filetype=asm %s -o - | FileCheck %s
+; RUN: llc -mtriple=aarch64-linux -filetype=obj %s -o - | \
+; RUN:   llvm-readelf -r -x .data.DW.ref.__gxx_personality_v0 - | \
+; RUN:   FileCheck --check-prefix=RELOC %s
+
+ at _ZTISt9exception = external constant ptr
+
+define i32 @main() personality ptr @__gxx_personality_v0 {
+entry:
+  invoke void @foo() to label %cont unwind label %lpad
+
+lpad:
+  %0 = landingpad { ptr, i32 }
+    catch ptr null
+    catch ptr @_ZTISt9exception
+  ret i32 0
+
+cont:
+  ret i32 0
+}
+
+declare i32 @__gxx_personality_v0(...)
+
+declare void @foo()
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 8, !"ptrauth-sign-personality", i32 1}
+
+; CHECK:      DW.ref.__gxx_personality_v0:
+; CHECK-NEXT:     .xword  __gxx_personality_v0 at AUTH(ia,32429,addr)
+
+; RELOC:      Relocation section '.rela.data.DW.ref.__gxx_personality_v0' at offset 0x2a0 contains 1 entries:
+; RELOC-NEXT:     Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
+; RELOC-NEXT: 0000000000000000  0000000f00000244 R_AARCH64_AUTH_ABS64   0000000000000000 __gxx_personality_v0 + 0
+
+; RELOC:      Hex dump of section '.data.DW.ref.__gxx_personality_v0':
+; RELOC-NEXT: 0x00000000 00000000 ad7e0080
+;                                 ^^^^ 0x7EAD = discriminator
+;                                       ^^ 0b10000000: bit 63 = 1 -> address diversity enabled, bits 61:60 = 0b00 -> key is IA



More information about the cfe-commits mailing list