i386: Insert ENDBR after __morestack call
Since __morestack will jump back to its callee via indirect call, we need to insert ENDBR after calling __morestack. gcc/ PR target/85388 * config/i386/i386.c (ix86_expand_split_stack_prologue): Insert ENDBR after calling __morestack. gcc/testsuite/ PR target/85388 * gcc.dg/pr85388-1.c: New test. * gcc.dg/pr85388-2.c: Likewise. * gcc.dg/pr85388-3.c: Likewise. * gcc.dg/pr85388-4.c: Likewise. * gcc.dg/pr85388-5.c: Likewise. * gcc.dg/pr85388-6.c: Likewise. From-SVN: r259475
This commit is contained in:
parent
05b1448061
commit
8953574fa9
@ -1,3 +1,9 @@
|
||||
2018-04-18 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
PR target/85388
|
||||
* config/i386/i386.c (ix86_expand_split_stack_prologue): Insert
|
||||
ENDBR after calling __morestack.
|
||||
|
||||
2018-04-18 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
PR jit/85384
|
||||
|
@ -15265,7 +15265,16 @@ ix86_expand_split_stack_prologue (void)
|
||||
instruction--we need control flow to continue at the subsequent
|
||||
label. Therefore, we use an unspec. */
|
||||
gcc_assert (crtl->args.pops_args < 65536);
|
||||
emit_insn (gen_split_stack_return (GEN_INT (crtl->args.pops_args)));
|
||||
rtx_insn *ret_insn
|
||||
= emit_insn (gen_split_stack_return (GEN_INT (crtl->args.pops_args)));
|
||||
|
||||
if ((flag_cf_protection & CF_BRANCH))
|
||||
{
|
||||
/* Insert ENDBR since __morestack will jump back here via indirect
|
||||
call. */
|
||||
rtx cet_eb = gen_nop_endbr ();
|
||||
emit_insn_after (cet_eb, ret_insn);
|
||||
}
|
||||
|
||||
/* If we are in 64-bit mode and this function uses a static chain,
|
||||
we saved %r10 in %rax before calling _morestack. */
|
||||
|
@ -1,3 +1,13 @@
|
||||
2018-04-18 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
PR target/85388
|
||||
* gcc.dg/pr85388-1.c: New test.
|
||||
* gcc.dg/pr85388-2.c: Likewise.
|
||||
* gcc.dg/pr85388-3.c: Likewise.
|
||||
* gcc.dg/pr85388-4.c: Likewise.
|
||||
* gcc.dg/pr85388-5.c: Likewise.
|
||||
* gcc.dg/pr85388-6.c: Likewise.
|
||||
|
||||
2018-04-18 Jan Hubicka <jh@suse.cz>
|
||||
Martin Liska <mliska@suse.cz>
|
||||
|
||||
|
50
gcc/testsuite/gcc.dg/pr85388-1.c
Normal file
50
gcc/testsuite/gcc.dg/pr85388-1.c
Normal file
@ -0,0 +1,50 @@
|
||||
/* This test needs to use setrlimit to set the stack size, so it can
|
||||
only run on Unix. */
|
||||
/* { dg-do run { target { i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } } */
|
||||
/* { dg-require-effective-target cet } */
|
||||
/* { dg-require-effective-target split_stack } */
|
||||
/* { dg-options "-fsplit-stack -fcf-protection -mcet" } */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
/* Use a noinline function to ensure that the buffer is not removed
|
||||
from the stack. */
|
||||
static void use_buffer (char *buf) __attribute__ ((noinline));
|
||||
static void
|
||||
use_buffer (char *buf)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
}
|
||||
|
||||
/* Each recursive call uses 10,000 bytes. We call it 1000 times,
|
||||
using a total of 10,000,000 bytes. If -fsplit-stack is not
|
||||
working, that will overflow our stack limit. */
|
||||
|
||||
static void
|
||||
down (int i)
|
||||
{
|
||||
char buf[10000];
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
use_buffer (buf);
|
||||
down (i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
struct rlimit r;
|
||||
|
||||
/* We set a stack limit because we are usually invoked via make, and
|
||||
make sets the stack limit to be as large as possible. */
|
||||
r.rlim_cur = 8192 * 1024;
|
||||
r.rlim_max = 8192 * 1024;
|
||||
if (setrlimit (RLIMIT_STACK, &r) != 0)
|
||||
abort ();
|
||||
down (1000);
|
||||
return 0;
|
||||
}
|
56
gcc/testsuite/gcc.dg/pr85388-2.c
Normal file
56
gcc/testsuite/gcc.dg/pr85388-2.c
Normal file
@ -0,0 +1,56 @@
|
||||
/* { dg-do run { target { i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } } */
|
||||
/* { dg-require-effective-target cet } */
|
||||
/* { dg-require-effective-target split_stack } */
|
||||
/* { dg-require-effective-target pthread_h } */
|
||||
/* { dg-options "-pthread -fsplit-stack -fcf-protection -mcet" } */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* Use a noinline function to ensure that the buffer is not removed
|
||||
from the stack. */
|
||||
static void use_buffer (char *buf) __attribute__ ((noinline));
|
||||
static void
|
||||
use_buffer (char *buf)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
}
|
||||
|
||||
/* Each recursive call uses 10,000 bytes. We call it 1000 times,
|
||||
using a total of 10,000,000 bytes. If -fsplit-stack is not
|
||||
working, that will overflow our stack limit. */
|
||||
|
||||
static void
|
||||
down (int i)
|
||||
{
|
||||
char buf[10000];
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
use_buffer (buf);
|
||||
down (i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
thread_routine (void *arg __attribute__ ((unused)))
|
||||
{
|
||||
down (1000);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int i;
|
||||
pthread_t tid;
|
||||
void *dummy;
|
||||
|
||||
i = pthread_create (&tid, NULL, thread_routine, NULL);
|
||||
if (i != 0)
|
||||
abort ();
|
||||
i = pthread_join (tid, &dummy);
|
||||
if (i != 0)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
65
gcc/testsuite/gcc.dg/pr85388-3.c
Normal file
65
gcc/testsuite/gcc.dg/pr85388-3.c
Normal file
@ -0,0 +1,65 @@
|
||||
/* This test needs to use setrlimit to set the stack size, so it can
|
||||
only run on Unix. */
|
||||
/* { dg-do run { target { i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } } */
|
||||
/* { dg-require-effective-target cet } */
|
||||
/* { dg-require-effective-target split_stack } */
|
||||
/* { dg-options "-fsplit-stack -fcf-protection -mcet" } */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
/* Use a noinline function to ensure that the buffer is not removed
|
||||
from the stack. */
|
||||
static void use_buffer (char *buf) __attribute__ ((noinline));
|
||||
static void
|
||||
use_buffer (char *buf)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
}
|
||||
|
||||
/* Each recursive call uses 10,000 bytes. We call it 1000 times,
|
||||
using a total of 10,000,000 bytes. If -fsplit-stack is not
|
||||
working, that will overflow our stack limit. */
|
||||
|
||||
static void
|
||||
down (int i, ...)
|
||||
{
|
||||
char buf[10000];
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, i);
|
||||
if (va_arg (ap, int) != 1
|
||||
|| va_arg (ap, int) != 2
|
||||
|| va_arg (ap, int) != 3
|
||||
|| va_arg (ap, int) != 4
|
||||
|| va_arg (ap, int) != 5
|
||||
|| va_arg (ap, int) != 6
|
||||
|| va_arg (ap, int) != 7
|
||||
|| va_arg (ap, int) != 8
|
||||
|| va_arg (ap, int) != 9
|
||||
|| va_arg (ap, int) != 10)
|
||||
abort ();
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
use_buffer (buf);
|
||||
down (i - 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
struct rlimit r;
|
||||
|
||||
/* We set a stack limit because we are usually invoked via make, and
|
||||
make sets the stack limit to be as large as possible. */
|
||||
r.rlim_cur = 8192 * 1024;
|
||||
r.rlim_max = 8192 * 1024;
|
||||
if (setrlimit (RLIMIT_STACK, &r) != 0)
|
||||
abort ();
|
||||
down (1000, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||
return 0;
|
||||
}
|
69
gcc/testsuite/gcc.dg/pr85388-4.c
Normal file
69
gcc/testsuite/gcc.dg/pr85388-4.c
Normal file
@ -0,0 +1,69 @@
|
||||
/* This test needs to use setrlimit to set the stack size, so it can
|
||||
only run on Unix. */
|
||||
/* { dg-do run { target { i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } } */
|
||||
/* { dg-require-effective-target cet } */
|
||||
/* { dg-require-effective-target split_stack } */
|
||||
/* { dg-options "-fsplit-stack -fcf-protection -mcet" } */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
/* Use a noinline function to ensure that the buffer is not removed
|
||||
from the stack. */
|
||||
static void use_buffer (char *buf, size_t) __attribute__ ((noinline));
|
||||
static void
|
||||
use_buffer (char *buf, size_t c)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < c; ++i)
|
||||
buf[i] = (char) i;
|
||||
}
|
||||
|
||||
/* Each recursive call uses 10 * i bytes. We call it 1000 times,
|
||||
using a total of 5,000,000 bytes. If -fsplit-stack is not working,
|
||||
that will overflow our stack limit. */
|
||||
|
||||
static void
|
||||
down1 (int i)
|
||||
{
|
||||
char buf[10 * i];
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
use_buffer (buf, 10 * i);
|
||||
down1 (i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Same thing, using alloca. */
|
||||
|
||||
static void
|
||||
down2 (int i)
|
||||
{
|
||||
char *buf = alloca (10 * i);
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
use_buffer (buf, 10 * i);
|
||||
down2 (i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
struct rlimit r;
|
||||
|
||||
/* We set a stack limit because we are usually invoked via make, and
|
||||
make sets the stack limit to be as large as possible. */
|
||||
r.rlim_cur = 8192 * 1024;
|
||||
r.rlim_max = 8192 * 1024;
|
||||
if (setrlimit (RLIMIT_STACK, &r) != 0)
|
||||
abort ();
|
||||
down1 (1000);
|
||||
down2 (1000);
|
||||
return 0;
|
||||
}
|
54
gcc/testsuite/gcc.dg/pr85388-5.c
Normal file
54
gcc/testsuite/gcc.dg/pr85388-5.c
Normal file
@ -0,0 +1,54 @@
|
||||
/* { dg-do run { target { i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } } */
|
||||
/* { dg-require-effective-target cet } */
|
||||
/* { dg-require-effective-target split_stack } */
|
||||
/* { dg-options "-fsplit-stack -fcf-protection -mcet" } */
|
||||
|
||||
/* This test is like split-3.c, but tests with a smaller stack frame,
|
||||
since that uses a different prologue. */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Use a noinline function to ensure that the buffer is not removed
|
||||
from the stack. */
|
||||
static void use_buffer (char *buf) __attribute__ ((noinline));
|
||||
static void
|
||||
use_buffer (char *buf)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
}
|
||||
|
||||
/* When using gold, the call to abort will force a stack split. */
|
||||
|
||||
static void
|
||||
down (int i, ...)
|
||||
{
|
||||
char buf[1];
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, i);
|
||||
if (va_arg (ap, int) != 1
|
||||
|| va_arg (ap, int) != 2
|
||||
|| va_arg (ap, int) != 3
|
||||
|| va_arg (ap, int) != 4
|
||||
|| va_arg (ap, int) != 5
|
||||
|| va_arg (ap, int) != 6
|
||||
|| va_arg (ap, int) != 7
|
||||
|| va_arg (ap, int) != 8
|
||||
|| va_arg (ap, int) != 9
|
||||
|| va_arg (ap, int) != 10)
|
||||
abort ();
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
use_buffer (buf);
|
||||
down (i - 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
down (1000, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||
return 0;
|
||||
}
|
56
gcc/testsuite/gcc.dg/pr85388-6.c
Normal file
56
gcc/testsuite/gcc.dg/pr85388-6.c
Normal file
@ -0,0 +1,56 @@
|
||||
/* { dg-do run { target { i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } } */
|
||||
/* { dg-require-effective-target cet } */
|
||||
/* { dg-require-effective-target split_stack } */
|
||||
/* { dg-options "-fsplit-stack -O2 -fcf-protection -mcet" } */
|
||||
/* { dg-options "-fsplit-stack -O2 -mno-accumulate-outgoing-args -fcf-protection -mcet" { target { { i?86-*-* x86_64-*-* } && ia32 } } } */
|
||||
|
||||
/* A case that used to fail on 32-bit x86 when optimizing and not
|
||||
using -maccumulate-args. The stack adjustment of the alloca got
|
||||
mixed up with the arguments pushed on the stack to the function
|
||||
before the call of alloca. */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct { const char* s; int l; } s;
|
||||
|
||||
typedef unsigned long long align16 __attribute__ ((aligned(16)));
|
||||
|
||||
s gobats (const void *, int) __attribute__ ((noinline));
|
||||
|
||||
s
|
||||
gobats (const void* p __attribute__ ((unused)),
|
||||
int l __attribute__ ((unused)))
|
||||
{
|
||||
s v;
|
||||
v.s = 0;
|
||||
v.l = 0;
|
||||
return v;
|
||||
}
|
||||
|
||||
void check_aligned (void *p) __attribute__ ((noinline));
|
||||
|
||||
void
|
||||
check_aligned (void *p)
|
||||
{
|
||||
if (((__SIZE_TYPE__) p & 0xf) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
void gap (void *) __attribute__ ((noinline));
|
||||
|
||||
void gap (void *p)
|
||||
{
|
||||
align16 a;
|
||||
check_aligned (&a);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
s *space;
|
||||
gobats(0, 16);
|
||||
space = (s *) alloca(sizeof(s) + 1);
|
||||
*space = (s){0, 16};
|
||||
gap(space);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user