aarch64: Fix missing BTI instruction in trampolines

If two functions require trampolines, and the first has BTI enabled
while the second doesn't, the generated template will be lacking
a BTI instruction.  This patch fixes this by always adding a BTI
instruction, which is safe as BTI instructions are ignored on
unsupported architecture versions.

2020-07-01  Omar Tahir  <omar.tahir@arm.com>

gcc/
	* config/aarch64/aarch64.c (aarch64_asm_trampoline_template): Always
	generate a BTI instruction.

gcc/testsuite/
	* gcc.target/aarch64/bti-4.c: New test.
This commit is contained in:
Omar Tahir 2020-07-01 21:56:16 +01:00 committed by Richard Sandiford
parent 553c657206
commit be7c41a556
2 changed files with 68 additions and 22 deletions

View file

@ -10833,40 +10833,26 @@ aarch64_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
return get_hard_reg_initial_val (Pmode, LR_REGNUM);
}
static void
aarch64_asm_trampoline_template (FILE *f)
{
int offset1 = 16;
int offset2 = 20;
if (aarch64_bti_enabled ())
{
asm_fprintf (f, "\thint\t34 // bti c\n");
offset1 -= 4;
offset2 -= 4;
}
/* Even if the current function doesn't have branch protection, some
later function might, so since this template is only generated once
we have to add a BTI just in case. */
asm_fprintf (f, "\thint\t34 // bti c\n");
if (TARGET_ILP32)
{
asm_fprintf (f, "\tldr\tw%d, .+%d\n", IP1_REGNUM - R0_REGNUM, offset1);
asm_fprintf (f, "\tldr\tw%d, .+%d\n", STATIC_CHAIN_REGNUM - R0_REGNUM,
offset1);
asm_fprintf (f, "\tldr\tw%d, .+12\n", IP1_REGNUM - R0_REGNUM);
asm_fprintf (f, "\tldr\tw%d, .+12\n", STATIC_CHAIN_REGNUM - R0_REGNUM);
}
else
{
asm_fprintf (f, "\tldr\t%s, .+%d\n", reg_names [IP1_REGNUM], offset1);
asm_fprintf (f, "\tldr\t%s, .+%d\n", reg_names [STATIC_CHAIN_REGNUM],
offset2);
asm_fprintf (f, "\tldr\t%s, .+12\n", reg_names [IP1_REGNUM]);
asm_fprintf (f, "\tldr\t%s, .+16\n", reg_names [STATIC_CHAIN_REGNUM]);
}
asm_fprintf (f, "\tbr\t%s\n", reg_names [IP1_REGNUM]);
/* The trampoline needs an extra padding instruction. In case if BTI is
enabled the padding instruction is replaced by the BTI instruction at
the beginning. */
if (!aarch64_bti_enabled ())
assemble_aligned_integer (4, const0_rtx);
assemble_aligned_integer (POINTER_BYTES, const0_rtx);
assemble_aligned_integer (POINTER_BYTES, const0_rtx);
}

View file

@ -0,0 +1,60 @@
/* { dg-do compile } */
/* If configured with --enable-standard-branch-protection, disable it. */
/* { dg-additional-options "-mbranch-protection=none" { target { default_branch_protection } } } */
void f1 (void *);
void f2 (void *);
void f3 (void *, void (*)(void *));
int
retbr_trampolines (void *a, int b)
{
if (!b)
{
f1 (a);
return 1;
}
if (b)
{
/* Suppress "ISO C forbids nested functions" warning. */
_Pragma("GCC diagnostic push")
_Pragma("GCC diagnostic ignored \"-Wpedantic\"")
void retbr_tramp_internal (void *c)
{
_Pragma("GCC diagnostic pop")
if (c == a)
f2 (c);
}
f3 (a, retbr_tramp_internal);
}
return 0;
}
__attribute__((target("branch-protection=bti,arch=armv8.3-a")))
int
retbr_trampolines2 (void *a, int b)
{
if (!b)
{
f1 (a);
return 1;
}
if (b)
{
/* Suppress "ISO C forbids nested functions" warning. */
_Pragma("GCC diagnostic push")
_Pragma("GCC diagnostic ignored \"-Wpedantic\"")
__attribute__((target("branch-protection=bti,arch=armv8.3-a")))
void retbr_tramp_internal2 (void *c)
{
_Pragma("GCC diagnostic pop")
if (c == a)
f2 (c);
}
f3 (a, retbr_tramp_internal2);
}
return 0;
}
/* Trampoline should have BTI C. */
/* { dg-final { scan-assembler "\.LTRAMP0:\n\thint\t34" } } */