From 5363c0289e3525139939bb678deeda98d06b2556 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Mon, 3 Feb 2020 10:22:57 -0800
Subject: [PATCH] i386: Define TARGET_ASM_PRINT_PATCHABLE_FUNCTION_ENTRY
Define TARGET_ASM_PRINT_PATCHABLE_FUNCTION_ENTRY to make sure that the
ENDBR are emitted before the patch area. When -mfentry -pg is also used
together, there should be no ENDBR before "call __fentry__".
gcc/
PR target/93492
* config/i386/i386.c (ix86_asm_output_function_label): Set
function_label_emitted to true.
(ix86_print_patchable_function_entry): New function.
gcc/testsuite/
PR target/93492
* gcc.target/i386/pr93492-1.c: New test.
* gcc.target/i386/pr93492-2.c: Likewise.
* gcc.target/i386/pr93492-3.c: Likewise.
---
gcc/config/i386/i386.c | 46 ++++++++++++++
gcc/config/i386/i386.h | 3 +
gcc/testsuite/gcc.target/i386/pr93492-1.c | 73 +++++++++++++++++++++++
gcc/testsuite/gcc.target/i386/pr93492-2.c | 12 ++++
gcc/testsuite/gcc.target/i386/pr93492-3.c | 13 ++++
5 files changed, 147 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/i386/pr93492-1.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr93492-2.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr93492-3.c
@@ -1563,6 +1563,9 @@ ix86_asm_output_function_label (FILE *asm_out_file, const char *fname,
{
bool is_ms_hook = ix86_function_ms_hook_prologue (decl);
+ if (cfun)
+ cfun->machine->function_label_emitted = true;
+
if (is_ms_hook)
{
int i, filler_count = (TARGET_64BIT ? 32 : 16);
@@ -9118,6 +9121,45 @@ ix86_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED)
}
}
+/* Implement TARGET_ASM_PRINT_PATCHABLE_FUNCTION_ENTRY. */
+
+void
+ix86_print_patchable_function_entry (FILE *file,
+ unsigned HOST_WIDE_INT patch_area_size,
+ bool record_p)
+{
+ if (cfun->machine->function_label_emitted)
+ {
+ if ((flag_cf_protection & CF_BRANCH)
+ && !lookup_attribute ("nocf_check",
+ TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl)))
+ && (!flag_manual_endbr
+ || lookup_attribute ("cf_check",
+ DECL_ATTRIBUTES (cfun->decl)))
+ && !cgraph_node::get (cfun->decl)->only_called_directly_p ())
+ {
+ /* Remove ENDBR that follows the patch area. */
+ rtx_insn *insn = next_real_nondebug_insn (get_insns ());
+ if (insn
+ && INSN_P (insn)
+ && GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
+ && XINT (PATTERN (insn), 1) == UNSPECV_NOP_ENDBR)
+ delete_insn (insn);
+
+ /* Remove the queued ENDBR. */
+ cfun->machine->endbr_queued_at_entrance = false;
+
+ /* Insert a ENDBR before the patch area right after the
+ function label and the .cfi_startproc directive. */
+ asm_fprintf (file, "\t%s\n",
+ TARGET_64BIT ? "endbr64" : "endbr32");
+ }
+ }
+
+ default_print_patchable_function_entry (file, patch_area_size,
+ record_p);
+}
+
/* Return a scratch register to use in the split stack prologue. The
split stack prologue is used for -fsplit-stack. It is the first
instructions in the function, even before the regular prologue.
@@ -22744,6 +22786,10 @@ ix86_run_selftests (void)
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE ix86_output_function_epilogue
+#undef TARGET_ASM_PRINT_PATCHABLE_FUNCTION_ENTRY
+#define TARGET_ASM_PRINT_PATCHABLE_FUNCTION_ENTRY \
+ ix86_print_patchable_function_entry
+
#undef TARGET_ENCODE_SECTION_INFO
#ifndef SUBTARGET_ENCODE_SECTION_INFO
#define TARGET_ENCODE_SECTION_INFO ix86_encode_section_info
@@ -2844,6 +2844,9 @@ struct GTY(()) machine_function {
/* If true, ENDBR is queued at function entrance. */
BOOL_BITFIELD endbr_queued_at_entrance : 1;
+ /* If true, the function label has been emitted. */
+ BOOL_BITFIELD function_label_emitted : 1;
+
/* True if the function needs a stack frame. */
BOOL_BITFIELD stack_frame_required : 1;
new file mode 100644
@@ -0,0 +1,73 @@
+/* { dg-do "compile" } */
+/* { dg-options "-O1 -fcf-protection -mmanual-endbr" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/* Note: this test only checks the instructions in the function bodies,
+ not the placement of the patch label or nops before the function. */
+
+/*
+**f10_none:
+** nop
+** ret
+*/
+void
+__attribute__ ((nocf_check,patchable_function_entry (1, 0)))
+f10_none ()
+{
+}
+
+/*
+**f10_endbr:
+** endbr(32|64)
+** nop
+** ret
+*/
+void
+__attribute__ ((cf_check,patchable_function_entry (1, 0)))
+f10_endbr (void)
+{
+}
+
+/*
+**f11_none:
+** ret
+*/
+void
+__attribute__ ((nocf_check,patchable_function_entry (1, 1)))
+f11_none ()
+{
+}
+
+/*
+**f11_endbr:
+** endbr(32|64)
+** ret
+*/
+void
+__attribute__ ((cf_check,patchable_function_entry (1, 1)))
+f11_endbr (void)
+{
+}
+
+/*
+**f21_none:
+** nop
+** ret
+*/
+void
+__attribute__ ((nocf_check,patchable_function_entry (2, 1)))
+f21_none ()
+{
+}
+
+/*
+**f21_endbr:
+** endbr(32|64)
+** nop
+** ret
+*/
+void
+__attribute__ ((cf_check,patchable_function_entry (2, 1)))
+f21_endbr ()
+{
+}
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do "compile" } */
+/* { dg-options "-O1 -fcf-protection -mmanual-endbr" } */
+
+/* Test the placement of the .LPFE1 label. */
+
+void
+__attribute__ ((cf_check,patchable_function_entry (1, 0)))
+f10_endbr ()
+{
+}
+
+/* { dg-final { scan-assembler "_?f10_endbr:\n\tendbr(32|64)\n.*\.LPFE1:\n\tnop\n.*\tret\n" } } */
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-do "compile" } */
+/* { dg-require-effective-target mfentry } */
+/* { dg-options "-O1 -fcf-protection -mmanual-endbr -mfentry -pg -fno-asynchronous-unwind-tables" } */
+
+/* Test the placement of the .LPFE1 label. */
+
+void
+__attribute__ ((cf_check,patchable_function_entry (1, 0)))
+f10_endbr ()
+{
+}
+
+/* { dg-final { scan-assembler "_?f10_endbr:\n\tendbr(32|64)\n.*\.LPFE1:\n\tnop\n1:\tcall\t__fentry__\n\tret\n" } } */
--
2.24.1