From: Thomas Preud'homme Date: Tue, 13 Dec 2016 09:39:02 +0000 (+0000) Subject: Fix PR77933: stack corruption on ARM when using high registers and LR X-Git-Tag: releases/gcc-5.5.0~645 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b8515887bf7b270d7d2c02ee1f62d649fd0fba03;p=thirdparty%2Fgcc.git Fix PR77933: stack corruption on ARM when using high registers and LR 2016-12-13 Thomas Preud'homme Backport from mainline 2016-11-17 Thomas Preud'homme gcc/ PR target/77933 * config/arm/arm.c (thumb1_expand_prologue): Distinguish between lr being live in the function and lr needing to be saved. Distinguish between already saved pushable registers and registers to push. Check for LR being an available pushable register. gcc/testsuite/ PR target/77933 * gcc.target/arm/pr77933-1.c: New test. * gcc.target/arm/pr77933-2.c: Likewise. From-SVN: r243600 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a6b3df545cde..43277e0e6504 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2016-12-13 Thomas Preud'homme + + Backport from mainline + 2016-11-17 Thomas Preud'homme + + PR target/77933 + * config/arm/arm.c (thumb1_expand_prologue): Distinguish between lr + being live in the function and lr needing to be saved. Distinguish + between already saved pushable registers and registers to push. + Check for LR being an available pushable register. + 2016-12-12 Bernd Schmidt Backport from mainline diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index c01a3c878968..5c975625bfa2 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -24457,6 +24457,7 @@ thumb1_expand_prologue (void) unsigned long live_regs_mask; unsigned long l_mask; unsigned high_regs_pushed = 0; + bool lr_needs_saving; func_type = arm_current_func_type (); @@ -24479,6 +24480,7 @@ thumb1_expand_prologue (void) offsets = arm_get_frame_offsets (); live_regs_mask = offsets->saved_regs_mask; + lr_needs_saving = live_regs_mask & (1 << LR_REGNUM); /* Extract a mask of the ones we can give to the Thumb's push instruction. */ l_mask = live_regs_mask & 0x40ff; @@ -24545,6 +24547,7 @@ thumb1_expand_prologue (void) { insn = thumb1_emit_multi_reg_push (l_mask, l_mask); RTX_FRAME_RELATED_P (insn) = 1; + lr_needs_saving = false; offset = bit_count (l_mask) * UNITS_PER_WORD; } @@ -24609,12 +24612,13 @@ thumb1_expand_prologue (void) be a push of LR and we can combine it with the push of the first high register. */ else if ((l_mask & 0xff) != 0 - || (high_regs_pushed == 0 && l_mask)) + || (high_regs_pushed == 0 && lr_needs_saving)) { unsigned long mask = l_mask; mask |= (1 << thumb1_extra_regs_pushed (offsets, true)) - 1; insn = thumb1_emit_multi_reg_push (mask, mask); RTX_FRAME_RELATED_P (insn) = 1; + lr_needs_saving = false; } if (high_regs_pushed) @@ -24632,7 +24636,9 @@ thumb1_expand_prologue (void) /* Here we need to mask out registers used for passing arguments even if they can be pushed. This is to avoid using them to stash the high registers. Such kind of stash may clobber the use of arguments. */ - pushable_regs = l_mask & (~arg_regs_mask) & 0xff; + pushable_regs = l_mask & (~arg_regs_mask); + if (lr_needs_saving) + pushable_regs &= ~(1 << LR_REGNUM); if (pushable_regs == 0) pushable_regs = 1 << thumb_find_work_register (live_regs_mask); @@ -24640,8 +24646,9 @@ thumb1_expand_prologue (void) while (high_regs_pushed > 0) { unsigned long real_regs_mask = 0; + unsigned long push_mask = 0; - for (regno = LAST_LO_REGNUM; regno >= 0; regno --) + for (regno = LR_REGNUM; regno >= 0; regno --) { if (pushable_regs & (1 << regno)) { @@ -24650,6 +24657,7 @@ thumb1_expand_prologue (void) high_regs_pushed --; real_regs_mask |= (1 << next_hi_reg); + push_mask |= (1 << regno); if (high_regs_pushed) { @@ -24659,23 +24667,20 @@ thumb1_expand_prologue (void) break; } else - { - pushable_regs &= ~((1 << regno) - 1); - break; - } + break; } } /* If we had to find a work register and we have not yet saved the LR then add it to the list of regs to push. */ - if (l_mask == (1 << LR_REGNUM)) + if (lr_needs_saving) { - pushable_regs |= l_mask; - real_regs_mask |= l_mask; - l_mask = 0; + push_mask |= 1 << LR_REGNUM; + real_regs_mask |= 1 << LR_REGNUM; + lr_needs_saving = false; } - insn = thumb1_emit_multi_reg_push (pushable_regs, real_regs_mask); + insn = thumb1_emit_multi_reg_push (push_mask, real_regs_mask); RTX_FRAME_RELATED_P (insn) = 1; } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f09906befb99..a60809152958 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2016-12-13 Thomas Preud'homme + + Backport from mainline + 2016-11-17 Thomas Preud'homme + + PR target/77933 + * gcc.target/arm/pr77933-1.c: New test. + * gcc.target/arm/pr77933-2.c: Likewise. + 2016-12-12 Bernd Schmidt Backport from mainline diff --git a/gcc/testsuite/gcc.target/arm/pr77933-1.c b/gcc/testsuite/gcc.target/arm/pr77933-1.c new file mode 100644 index 000000000000..95cf68ea7531 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/pr77933-1.c @@ -0,0 +1,46 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +__attribute__ ((noinline, noclone)) void +clobber_lr_and_highregs (void) +{ + __asm__ volatile ("" : : : "r8", "r9", "lr"); +} + +int +main (void) +{ + int ret; + + __asm volatile ("mov\tr4, #0xf4\n\t" + "mov\tr5, #0xf5\n\t" + "mov\tr6, #0xf6\n\t" + "mov\tr7, #0xf7\n\t" + "mov\tr0, #0xf8\n\t" + "mov\tr8, r0\n\t" + "mov\tr0, #0xfa\n\t" + "mov\tr10, r0" + : : : "r0", "r4", "r5", "r6", "r7", "r8", "r10"); + + clobber_lr_and_highregs (); + + __asm volatile ("cmp\tr4, #0xf4\n\t" + "bne\tfail\n\t" + "cmp\tr5, #0xf5\n\t" + "bne\tfail\n\t" + "cmp\tr6, #0xf6\n\t" + "bne\tfail\n\t" + "cmp\tr7, #0xf7\n\t" + "bne\tfail\n\t" + "mov\tr0, r8\n\t" + "cmp\tr0, #0xf8\n\t" + "bne\tfail\n\t" + "mov\tr0, r10\n\t" + "cmp\tr0, #0xfa\n\t" + "bne\tfail\n\t" + "mov\t%0, #1\n" + "fail:\n\t" + "sub\tr0, #1" + : "=r" (ret) : :); + return ret; +} diff --git a/gcc/testsuite/gcc.target/arm/pr77933-2.c b/gcc/testsuite/gcc.target/arm/pr77933-2.c new file mode 100644 index 000000000000..9028c4fcab42 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/pr77933-2.c @@ -0,0 +1,47 @@ +/* { dg-do run } */ +/* { dg-skip-if "" { ! { arm_thumb1_ok || arm_thumb2_ok } } } */ +/* { dg-options "-mthumb -O2 -mtpcs-leaf-frame" } */ + +__attribute__ ((noinline, noclone)) void +clobber_lr_and_highregs (void) +{ + __asm__ volatile ("" : : : "r8", "r9", "lr"); +} + +int +main (void) +{ + int ret; + + __asm volatile ("mov\tr4, #0xf4\n\t" + "mov\tr5, #0xf5\n\t" + "mov\tr6, #0xf6\n\t" + "mov\tr7, #0xf7\n\t" + "mov\tr0, #0xf8\n\t" + "mov\tr8, r0\n\t" + "mov\tr0, #0xfa\n\t" + "mov\tr10, r0" + : : : "r0", "r4", "r5", "r6", "r7", "r8", "r10"); + + clobber_lr_and_highregs (); + + __asm volatile ("cmp\tr4, #0xf4\n\t" + "bne\tfail\n\t" + "cmp\tr5, #0xf5\n\t" + "bne\tfail\n\t" + "cmp\tr6, #0xf6\n\t" + "bne\tfail\n\t" + "cmp\tr7, #0xf7\n\t" + "bne\tfail\n\t" + "mov\tr0, r8\n\t" + "cmp\tr0, #0xf8\n\t" + "bne\tfail\n\t" + "mov\tr0, r10\n\t" + "cmp\tr0, #0xfa\n\t" + "bne\tfail\n\t" + "mov\t%0, #1\n" + "fail:\n\t" + "sub\tr0, #1" + : "=r" (ret) : :); + return ret; +}