[PATCH v3 1/8] newlib: libc: define M-profile PACBTI-enablement macros

"Victor L. Do Nascimento" <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
Hi all,

This patch augments the arm_asm.h header file to provide support for
PACBTI enablement via macros for hand-written assembly functions,
updating both prologues/epilogues as well as cfi-related directives
depending on the compile-time mbranch-protection argument values.

It defines the following preprocessor macros:
   * HAVE_PAC_LEAF: Indicates whether pac-signing has been requested for
   leaf functions.
   * PAC_LEAF_PUSH_IP: Whether leaf functions should push the pac code
   to the stack irrespective of whether the ip register is clobbered in
   the function or not.
   * PAC_CFI_ADJUST: Given values for the above two parameters, this
   holds the calculated offset applied to default CFI address/offset
   values as a consequence of potentially pushing the pac-code to the
   stack.

It also defines the following assembler macros:
   * prologue: In addition to pushing any callee-saved registers onto
   the stack, it generates any requested pacbti instructions.
   Pushed registers are specified via the optional `first', `last' and
   `savepac' macro argument parameters.
   when a single register number is provided, it pushes that
   register.  When two register numbers are provided, they specify a
   range to save.  If savepac is non-zero, the ip register is also
   saved.
   For example:

       prologue savepac=1 -> push {ip}
       prologue 1 -> push {r1}
       prologue 1 savepac=1 -> push {r1, ip}
       prologue 1 4 -> push {r1-r4}
       prologue 1 4 savepac=1 -> push {r1-r4, ip}

   * epilogue: pops registers off the stack and emits pac key signing
   instruction if requested. The optional `first', `last' and
   `savepac' function as per the prologue macro, generating a pop
   instead of push instruction.
   * cfisavelist - prologue macro helper function, generating
   necessary .cfi_offset directives associated with push instruction.
   Therefore, the net effect of calling `prologue 1 2 savepac=1' is
   to generate the following:

       push {r1-r2, ip}
       .cfi_adjust_cfa_offset 12
       .cfi_offset 143, -12
       .cfi_offset 2, -8
       .cfi_offset 1, -4

   * cfirestorelist - epilogue macro helper function, emitting
   .cfi_restore instructions prior to resetting the cfa offset.  As
   such, calling `epilogue 1 2 savepac=1' will produce:

        pop {r1-r2, ip}
	.cfi_restore 143
	.cfi_restore 2
	.cfi_restore 1
	.cfi_def_cfa_offset 0

Regards,
Victor

---
 newlib/libc/machine/arm/arm_asm.h | 130 ++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)

diff --git a/newlib/libc/machine/arm/arm_asm.h b/newlib/libc/machine/arm/arm_asm.h
index 2708057de..d314094c9 100644
--- a/newlib/libc/machine/arm/arm_asm.h
+++ b/newlib/libc/machine/arm/arm_asm.h
@@ -60,4 +60,134 @@
 # define _ISA_THUMB_1
 #endif
 
+/* Check whether leaf function PAC signing has been requested in the
+   -mbranch-protect compile-time option.  */
+#define LEAF_PROTECT_BIT 2
+
+#ifdef __ARM_FEATURE_PAC_DEFAULT
+# define HAVE_PAC_LEAF \
+	__ARM_FEATURE_PAC_DEFAULT & (1 << LEAF_PROTECT_BIT)
+#else
+# define HAVE_PAC_LEAF 0
+#endif
+
+/* Provide default parameters for PAC-code handling in leaf-functions.  */
+#ifndef PAC_LEAF_PUSH_IP
+# define PAC_LEAF_PUSH_IP 0
+#endif
+
+#if HAVE_PAC_LEAF
+# if PAC_LEAF_PUSH_IP
+#   define PAC_CFI_ADJ 4
+# else
+#  define PAC_CFI_ADJ 0
+# endif /* PAC_LEAF_PUSH_IP*/
+#else
+# undef PAC_LEAF_PUSH_IP
+# define PAC_LEAF_PUSH_IP 0
+# define PAC_CFI_ADJ 0
+#endif /* HAVE_PAC_LEAF */
+
+#ifdef __ASSEMBLER__
+/* Emit .cfi_restore directives for a consecutive sequence of registers.  */
+	.macro cfirestorelist first, last
+	.cfi_restore \last
+	.if \last-\first
+	cfirestorelist \first, \last-1
+	.endif
+	.endm
+
+/* Emit .cfi_offset directives for a consecutive sequence of registers.  */
+	.macro cfisavelist first, last, index=1
+	.cfi_offset \last, -4*(\index) - PAC_CFI_ADJ
+	.if \last-\first
+	cfisavelist \first, \last-1, \index+1
+	.endif
+	.endm
+
+/* Create a prologue entry sequence handling PAC/BTI, if required and emitting
+   CFI directives for generated PAC code and any pushed registers.  */
+	.macro prologue first=-1, last=-1, savepac=PAC_LEAF_PUSH_IP
+#if HAVE_PAC_LEAF
+#if __ARM_FEATURE_BTI_DEFAULT
+	pacbti	ip, lr, sp
+#else
+	pac	ip, lr, sp
+#endif /* __ARM_FEATURE_BTI_DEFAULT */
+	.cfi_register 143, 12
+#else
+#if __ARM_FEATURE_BTI_DEFAULT
+	bti
+#endif /* __ARM_FEATURE_BTI_DEFAULT */
+#endif /* HAVE_PAC_LEAF */
+	.if \first != -1
+	.if \last != -1
+	.if \savepac
+	push {r\first-r\last, ip}
+	.cfi_adjust_cfa_offset ((\last-\first)+1)*4 + PAC_CFI_ADJ
+	.cfi_offset 143, -PAC_CFI_ADJ
+	cfisavelist \first, \last
+	.else
+	push {r\first-r\last}
+	.cfi_adjust_cfa_offset ((\last-\first)+1)*4
+	cfisavelist \first, \last
+	.endif
+	.else
+	.if \savepac
+	push {r\first, ip}
+	.cfi_adjust_cfa_offset 4 + PAC_CFI_ADJ
+	.cfi_offset 143, -PAC_CFI_ADJ 
+	cfisavelist \first, \first
+	.else // !\savepac
+	push {r\first}
+	.cfi_adjust_cfa_offset PAC_CFI_ADJ
+	cfisavelist \first, \first
+	.endif
+	.endif
+	.else // \first == -1
+	.if \savepac
+	push {ip}
+	.cfi_adjust_cfa_offset PAC_CFI_ADJ
+	.cfi_offset 143, -PAC_CFI_ADJ
+	.endif
+	.endif
+	.endm
+
+/* Create an epilogue exit sequence handling PAC/BTI, if required and emitting
+  CFI directives for all restored registers.  */
+	.macro epilogue first=-1, last=-1, savepac=PAC_LEAF_PUSH_IP
+	.if \first != -1
+	.if \last != -1
+	.if \savepac
+	pop {r\first-r\last, ip}
+	.cfi_restore 143
+	cfirestorelist \first, \last
+	.else
+	pop {r\first-r\last}
+	cfirestorelist \first, \last
+	.endif
+	.else
+	.if \savepac
+	pop {r\first, ip}
+	.cfi_restore 143
+	cfirestorelist \first, \first
+	.else
+	pop {r\first}
+	cfirestorelist \first, \first
+	.endif
+	.endif
+	.else
+	.if \savepac
+	pop {ip}
+	.cfi_restore 143
+	.endif
+	.endif
+	.cfi_def_cfa_offset 0
+#if HAVE_PAC_LEAF
+	aut	ip, lr, sp
+#endif /* HAVE_PAC_LEAF */
+	bx	lr
+	.endm
+#endif /* __ASSEMBLER__ */
+
 #endif /* ARM_ASM__H */
-- 
2.36.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.