summaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.target/arm/pr85434.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/testsuite/gcc.target/arm/pr85434.c')
-rw-r--r--gcc/testsuite/gcc.target/arm/pr85434.c200
1 files changed, 200 insertions, 0 deletions
diff --git a/gcc/testsuite/gcc.target/arm/pr85434.c b/gcc/testsuite/gcc.target/arm/pr85434.c
new file mode 100644
index 00000000000..4143a861f7c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr85434.c
@@ -0,0 +1,200 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target fstack_protector }*/
+/* { dg-require-effective-target fpic }*/
+/* { dg-additional-options "-Os -fpic -fstack-protector-strong" } */
+
+#include <stddef.h>
+#include <stdint.h>
+
+
+static const unsigned char base64_enc_map[64] =
+{
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
+ 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', '+', '/'
+};
+
+#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
+
+
+void doSmth(void *x);
+
+#include <string.h>
+
+
+void check(int n) {
+
+ if (!(n % 2 && n % 3 && n % 5)) {
+ __asm__ ( "add r8, r8, #1;" );
+ }
+}
+
+uint32_t test(
+ uint32_t a1,
+ uint32_t a2,
+ size_t a3,
+ size_t a4,
+ size_t a5,
+ size_t a6)
+{
+ uint32_t nResult = 0;
+ uint8_t* h = 0L;
+ uint8_t X[128];
+ uint8_t mac[64];
+ size_t len;
+
+ doSmth(&a1);
+ doSmth(&a2);
+ doSmth(&a3);
+ doSmth(&a4);
+ doSmth(&a5);
+ doSmth(&a6);
+
+ if (a1 && a2 && a3 && a4 && a5 && a6) {
+ nResult = 1;
+ h = (void*)X;
+ len = sizeof(X);
+ memset(X, a2, len);
+ len -= 64;
+ memcpy(mac ,X, len);
+ *(h + len) = a6;
+
+ {
+
+
+ unsigned char *dst = X;
+ size_t dlen = a3;
+ size_t *olen = &a6;
+ const unsigned char *src = mac;
+ size_t slen = a4;
+ size_t i, n;
+ int C1, C2, C3;
+ unsigned char *p;
+
+ if( slen == 0 )
+ {
+ *olen = 0;
+ return( 0 );
+ }
+
+ n = slen / 3 + ( slen % 3 != 0 );
+
+ if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
+ {
+ *olen = BASE64_SIZE_T_MAX;
+ return( 0 );
+ }
+
+ n *= 4;
+
+ if( ( dlen < n + 1 ) || ( NULL == dst ) )
+ {
+ *olen = n + 1;
+ return( 0 );
+ }
+
+ n = ( slen / 3 ) * 3;
+
+ for( i = 0, p = dst; i < n; i += 3 )
+ {
+ C1 = *src++;
+ C2 = *src++;
+ C3 = *src++;
+
+ check(i);
+
+ *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+ *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+ *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
+ *p++ = base64_enc_map[C3 & 0x3F];
+ }
+
+ if( i < slen )
+ {
+ C1 = *src++;
+ C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
+
+ *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+ *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+
+ if( ( i + 1 ) < slen )
+ *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
+ else *p++ = '=';
+
+ *p++ = '=';
+ }
+
+ *olen = p - dst;
+ *p = 0;
+
+}
+
+ __asm__ ("mov r8, %0;" : "=r" ( nResult ));
+ }
+ else
+ {
+ nResult = 2;
+ }
+
+ doSmth(X);
+ doSmth(mac);
+
+
+ return nResult;
+}
+
+/* The pattern below catches sequences of instructions that were generated
+ for ARM and Thumb-2 before the fix for this PR. They are of the form:
+
+ ldr rX, <offset from sp or fp>
+ <optional non ldr instructions>
+ ldr rY, <offset from sp or fp>
+ ldr rZ, [rX]
+ <optional non ldr instructions>
+ cmp rY, rZ
+ <optional non cmp instructions>
+ bl __stack_chk_fail
+
+ Ideally the optional block would check for the various rX, rY and rZ
+ registers not being set but this is not possible due to back references
+ being illegal in lookahead expression in Tcl, thus preventing to use the
+ only construct that allow to negate a regexp from using the backreferences
+ to those registers. Instead we go for the heuristic of allowing non ldr/cmp
+ instructions with the assumptions that (i) those are not part of the stack
+ protector sequences and (ii) they would only be scheduled here if they don't
+ conflict with registers used by stack protector.
+
+ Note on the regexp logic:
+ Allowing non X instructions (where X is ldr or cmp) is done by looking for
+ some non newline spaces, followed by something which is not X, followed by
+ an alphanumeric character followed by anything but a newline and ended by a
+ newline the whole thing an undetermined number of times. The alphanumeric
+ character is there to force the match of the negative lookahead for X to
+ only happen after all the initial spaces and thus to check the mnemonic.
+ This prevents it to match one of the initial space. */
+/* { dg-final { scan-assembler-not {ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\]\n[ \t]+ldr[ \t]+([^,]+), \[\1\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+cmp[ \t]+\2, \3(?:\n[ \t]+(?!cmp)\w[^\n]*)*\n[ \t]+bl[ \t]+__stack_chk_fail} } } */
+
+/* Likewise for Thumb-1 sequences of instructions prior to the fix for this PR
+ which had the form:
+
+ ldr rS, <offset from sp or fp>
+ <optional non ldr instructions>
+ ldr rT, <PC relative offset>
+ <optional non ldr instructions>
+ ldr rX, [rS, rT]
+ <optional non ldr instructions>
+ ldr rY, <offset from sp or fp>
+ ldr rZ, [rX]
+ <optional non ldr instructions>
+ cmp rY, rZ
+ <optional non cmp instructions>
+ bl __stack_chk_fail
+
+ Note on the regexp logic:
+ PC relative offset is checked by looking for a source operand that does not
+ contain [ or ]. */
+/* { dg-final { scan-assembler-not {ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), [^][\n]*(?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), \[\1, \2\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\]\n[ \t]+ldr[ \t]+([^,]+), \[\3\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+cmp[ \t]+\4, \5(?:\n[ \t]+(?!cmp)\w[^\n]*)*\n[ \t]+bl[ \t]+__stack_chk_fail} } } */