From: Indu Bhagat <[email protected]>
Add basic tests for memtag-stack sanitizer. Memtag stack sanitizer
uses target hooks to emit AArch64 specific MTE instructions.
gcc/testsuite:
* lib/target-supports.exp:
* gcc.target/aarch64/memtag/alloca-1.c: New test.
* gcc.target/aarch64/memtag/alloca-2.c: New test.
* gcc.target/aarch64/memtag/alloca-3.c: New test.
* gcc.target/aarch64/memtag/arguments-1.c: New test.
* gcc.target/aarch64/memtag/arguments-2.c: New test.
* gcc.target/aarch64/memtag/arguments-3.c: New test.
* gcc.target/aarch64/memtag/arguments-4.c: New test.
* gcc.target/aarch64/memtag/arguments.c: New test.
* gcc.target/aarch64/memtag/basic-1.c: New test.
* gcc.target/aarch64/memtag/basic-3.c: New test.
* gcc.target/aarch64/memtag/basic-struct.c: New test.
* gcc.target/aarch64/memtag/large-array.c: New test.
* gcc.target/aarch64/memtag/local-no-escape.c: New test.
* gcc.target/aarch64/memtag/memtag.exp: New file.
* gcc.target/aarch64/memtag/no-sanitize-attribute.c: New test.
* gcc.target/aarch64/memtag/value-init.c: New test.
* gcc.target/aarch64/memtag/vararray-gimple.c: New test.
* gcc.target/aarch64/memtag/vararray.c: New test.
* gcc.target/aarch64/memtag/zero-init.c: New test.
* gcc.target/aarch64/memtag/texec-1.c: New test.
* gcc.target/aarch64/memtag/texec-2.c: New test.
* gcc.target/aarch64/memtag/texec-3.c: New test.
* gcc.target/aarch64/memtag/vla-1.c: New test.
* gcc.target/aarch64/memtag/vla-2.c: New test.
* testsuite/lib/target-supports.exp
(check_effective_target_aarch64_mte): New funcction.
Co-authored-by: Indu Bhagat <[email protected]>
Signed-off-by: Claudiu Zissulescu <[email protected]>
---
.../gcc.target/aarch64/memtag/alloca-1.c | 14 ++++++
.../gcc.target/aarch64/memtag/alloca-2.c | 15 ++++++
.../gcc.target/aarch64/memtag/alloca-3.c | 27 +++++++++++
.../gcc.target/aarch64/memtag/arguments-1.c | 3 ++
.../gcc.target/aarch64/memtag/arguments-2.c | 3 ++
.../gcc.target/aarch64/memtag/arguments-3.c | 3 ++
.../gcc.target/aarch64/memtag/arguments-4.c | 16 +++++++
.../gcc.target/aarch64/memtag/arguments.c | 3 ++
.../gcc.target/aarch64/memtag/basic-1.c | 14 ++++++
.../gcc.target/aarch64/memtag/basic-3.c | 28 +++++++++++
.../gcc.target/aarch64/memtag/basic-struct.c | 22 +++++++++
.../aarch64/memtag/cfi-mte-memtag-frame-1.c | 11 +++++
.../gcc.target/aarch64/memtag/large-array.c | 23 +++++++++
.../aarch64/memtag/local-no-escape.c | 22 +++++++++
.../gcc.target/aarch64/memtag/memtag.exp | 32 +++++++++++++
.../gcc.target/aarch64/memtag/mte-sig.h | 15 ++++++
.../aarch64/memtag/no-sanitize-attribute.c | 18 +++++++
.../gcc.target/aarch64/memtag/texec-1.c | 27 +++++++++++
.../gcc.target/aarch64/memtag/texec-2.c | 22 +++++++++
.../gcc.target/aarch64/memtag/texec-3.c | 37 ++++++++++++++
.../gcc.target/aarch64/memtag/value-init.c | 14 ++++++
.../aarch64/memtag/vararray-gimple.c | 16 +++++++
.../gcc.target/aarch64/memtag/vararray.c | 14 ++++++
.../gcc.target/aarch64/memtag/vla-1.c | 39 +++++++++++++++
.../gcc.target/aarch64/memtag/vla-2.c | 48 +++++++++++++++++++
.../gcc.target/aarch64/memtag/zero-init.c | 14 ++++++
gcc/testsuite/lib/target-supports.exp | 43 +++++++++++++++++
27 files changed, 543 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/alloca-1.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/alloca-2.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/alloca-3.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/arguments-1.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/arguments-2.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/arguments-3.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/arguments-4.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/arguments.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/basic-1.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/basic-3.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/basic-struct.c
create mode 100644
gcc/testsuite/gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/large-array.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/local-no-escape.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/memtag.exp
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/mte-sig.h
create mode 100644
gcc/testsuite/gcc.target/aarch64/memtag/no-sanitize-attribute.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/texec-1.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/texec-2.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/texec-3.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/value-init.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/vararray-gimple.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/vararray.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/vla-1.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/vla-2.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/zero-init.c
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/alloca-1.c
b/gcc/testsuite/gcc.target/aarch64/memtag/alloca-1.c
new file mode 100644
index 00000000000..c790ef5aeb3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/alloca-1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+extern int use (int *b);
+
+int foo (int n)
+{
+ int *b = __builtin_alloca (n);
+ int a = use (b);
+ return a;
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {\tstg\t...?, \[...?\], 16\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/alloca-2.c
b/gcc/testsuite/gcc.target/aarch64/memtag/alloca-2.c
new file mode 100644
index 00000000000..862dc818a97
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/alloca-2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+/* Check if we handle alloca size zero cases. */
+int a, b, c;
+void foo (void)
+{
+ int *d = __builtin_alloca (0);
+ for (;; a = b)
+ d[c] = *d;
+}
+
+/* We check if and only if we tag the 'd' variable. */
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {stg\t...?, \[sp\]\n} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/alloca-3.c
b/gcc/testsuite/gcc.target/aarch64/memtag/alloca-3.c
new file mode 100644
index 00000000000..c3be277b2e3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/alloca-3.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+extern int use (int *b);
+
+extern int n1;
+extern int n2;
+extern int n3;
+
+int foo (void)
+{
+ int *b1 = __builtin_alloca (n1);
+ int *b2 = __builtin_alloca (n2);
+ int *b3 = __builtin_alloca (n3);
+ int a1 = use (b1);
+ int a2 = use (b2);
+ int a3 = use (b3);
+
+ return a1+a2+a3;
+}
+
+/* With HWASAN_ALLOCA_POISON now calling irg of its own, the number of
+ expected irg is 3 and stg is 4 (3 for tag, 1 for untag each in their
+ respective loop). */
+
+/* { dg-final { scan-assembler-times {\tirg\t} 3 } } */
+/* { dg-final { scan-assembler-times {stg\t...?, \[...?\], 16\n} 4 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/arguments-1.c
b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-1.c
new file mode 100644
index 00000000000..f95b148d9f0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-1.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=kernel-hwaddress" } */
+/* { dg-error ".*'-fsanitize=memtag-stack' is incompatible with
'-fsanitize=kernel-hwaddress'.*" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/arguments-2.c
b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-2.c
new file mode 100644
index 00000000000..9a76c5e2d71
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-2.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=kernel-address" } */
+/* { dg-error ".*'-fsanitize=memtag-stack' is incompatible with
'-fsanitize=kernel-address'.*" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/arguments-3.c
b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-3.c
new file mode 100644
index 00000000000..e4eaee8edf2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-3.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "--param hwasan-random-frame-tag=0" } */
+/* { dg-warning "is ignored when \'-fsanitize=memtag-stack\' is present" "" {
target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/arguments-4.c
b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-4.c
new file mode 100644
index 00000000000..98035c84666
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-4.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2 -fno-sanitize=memtag-stack" } */
+
+int use (int * x);
+
+void foo (int n)
+{
+ int x = 99;
+ use (&x);
+}
+
+/* { dg-final { scan-assembler-not "\tirg" } } */
+/* { dg-final { scan-assembler-not "\tstg" } } */
+/* { dg-final { scan-assembler-not "\tst2g" } } */
+/* { dg-final { scan-assembler-not "\tsubg" } } */
+/* { dg-final { scan-assembler-not "\taddg" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/arguments.c
b/gcc/testsuite/gcc.target/aarch64/memtag/arguments.c
new file mode 100644
index 00000000000..ea1209f6a37
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/arguments.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=address" } */
+/* { dg-error ".*'-fsanitize=memtag-stack' is incompatible with
'-fsanitize=address'.*" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/basic-1.c
b/gcc/testsuite/gcc.target/aarch64/memtag/basic-1.c
new file mode 100644
index 00000000000..353e6974963
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/basic-1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+int use (int *x);
+
+void foo (int n)
+{
+ int x = 99;
+ use (&x);
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {\tstg\t} 2 } } */
+/* { dg-final { scan-assembler-not "\taddg" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/basic-3.c
b/gcc/testsuite/gcc.target/aarch64/memtag/basic-3.c
new file mode 100644
index 00000000000..3621454b619
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/basic-3.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+int use (int *x);
+
+void foo (int n)
+{
+ int a, b, c;
+ use (&a);
+ use (&b);
+ use (&c);
+}
+
+/* 3 stack vars need 48 bytes (16 bytes granule x 3). Each granule holds the
+ local variable stack address (8 bytes), and a padding (8 bytes). The rest
+ of the stack holds LR and temporary varaibles (i.e., x19, x20, and x29).
+
+ Expected: 3 stg to tag, 1 st2g + 1 stg to untag. */
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {\taddg\t...?} 2 } } */
+/* { dg-final { scan-assembler-times {\tsubg\t...?} 3 } } */
+/* { dg-final { scan-assembler-times {\tstg\t...?, \[sp, 48\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tst2g\t...?, \[sp, 32\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tstg\t...?, \[sp, 32\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tstg\t...?, \[sp, 64\]\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tstp\tx19, x20, \[sp, 16\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tstp\tx29, x30, \[sp, -80]!\n} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/basic-struct.c
b/gcc/testsuite/gcc.target/aarch64/memtag/basic-struct.c
new file mode 100644
index 00000000000..98bf761967b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/basic-struct.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+struct A
+{
+ long a;
+ long b;
+ long c;
+ long d;
+};
+
+extern void use (struct A *a);
+
+long f (void)
+{
+ struct A a = {0, 0, 64, (long) &a};
+ use (&a);
+ return a.b;
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {\tst2g\t} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c
b/gcc/testsuite/gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c
new file mode 100644
index 00000000000..07cd03c2fd0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+
+int use (int *x);
+
+void foo (int n)
+{
+ int x = 99;
+ use (&x);
+}
+
+/* { dg-final { scan-assembler-times ".cfi_mte_tagged_frame" 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/large-array.c
b/gcc/testsuite/gcc.target/aarch64/memtag/large-array.c
new file mode 100644
index 00000000000..ae8006fd7f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/large-array.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+#define ARRAY_LEN 12000
+
+int create (void);
+
+void sort (int *data, int n);
+
+void sort_array (void)
+{
+ int data[ARRAY_LEN], i;
+
+ for (i=0; i < ARRAY_LEN; ++i)
+ {
+ data[i] = create ();
+ }
+
+ sort (data, ARRAY_LEN);
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {st2g\t...?, \[...?\], 32\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/local-no-escape.c
b/gcc/testsuite/gcc.target/aarch64/memtag/local-no-escape.c
new file mode 100644
index 00000000000..8c047582111
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/local-no-escape.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O0" } */
+
+/* Local variable 'x' is saved on the stack. */
+
+extern int use (int *x);
+extern int bar (int *x);
+extern int baz (int *x);
+
+int a[10];
+
+int foo (int n)
+{
+ int x = use (a);
+ if (x)
+ return bar (a);
+ else
+ return baz (a);
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {\tsubg\t...?} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/memtag.exp
b/gcc/testsuite/gcc.target/aarch64/memtag/memtag.exp
new file mode 100644
index 00000000000..d20cdf580b0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/memtag.exp
@@ -0,0 +1,32 @@
+# Copyright (C) 2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+if [check_effective_target_aarch64_mte] {
+ dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \
+ "" "-fsanitize=memtag-stack -march=armv8.5-a+memtag"
+}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/mte-sig.h
b/gcc/testsuite/gcc.target/aarch64/memtag/mte-sig.h
new file mode 100644
index 00000000000..efb3c6d187c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/mte-sig.h
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+
+void handler (int nSig)
+{
+ /* We hit the exception. Return error. */
+ exit (1);
+}
+
+
+static void setHandler (void)
+{
+ signal (SIGSEGV, handler);
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/no-sanitize-attribute.c
b/gcc/testsuite/gcc.target/aarch64/memtag/no-sanitize-attribute.c
new file mode 100644
index 00000000000..48ca9cf434f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/no-sanitize-attribute.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+int use (int *x);
+
+__attribute__((no_sanitize("memtag-stack")))
+void foo (int n)
+{
+ int x = 99;
+ use (&x);
+}
+
+/* { dg-final { scan-assembler-not "\tirg" } } */
+/* { dg-final { scan-assembler-not "\tgmi" } } */
+/* { dg-final { scan-assembler-not "\tstg" } } */
+/* { dg-final { scan-assembler-not "\tst2g" } } */
+/* { dg-final { scan-assembler-not "\tsubg" } } */
+/* { dg-final { scan-assembler-not "\taddg" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/texec-1.c
b/gcc/testsuite/gcc.target/aarch64/memtag/texec-1.c
new file mode 100644
index 00000000000..b63619b04d3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/texec-1.c
@@ -0,0 +1,27 @@
+/* { dg-do run { xfail *-*-* } } */
+/* { dg-require-effective-target memtag_exec } */
+/* { dg-additional-options "-O2" } */
+
+#include "mte-sig.h"
+
+void __attribute__((noinline))
+use (volatile unsigned char *ptr)
+{
+ ptr[0] = 0x41;
+ ptr[1] = 0x42;
+}
+
+int main(void)
+{
+ volatile unsigned char array[15];
+ volatile unsigned char *ptr = &array[0];
+
+ setHandler();
+ use (ptr);
+
+ /* Write to memory beyond the 16 byte granule (offsest 0x10) MTE should
+ generate an exception If the offset is less than 0x10 no SIGSEGV will
+ occur. */
+ ptr[0x10] = 0x55;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/texec-2.c
b/gcc/testsuite/gcc.target/aarch64/memtag/texec-2.c
new file mode 100644
index 00000000000..0fbbe2f0778
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/texec-2.c
@@ -0,0 +1,22 @@
+/* { dg-do run { xfail *-*-* } } */
+/* { dg-require-effective-target memtag_exec } */
+/* { dg-additional-options "-O2" } */
+#include "mte-sig.h"
+
+void __attribute__((noinline))
+use (volatile unsigned char *ptr)
+{
+ ptr[0] = 0x41;
+ ptr[1] = 0x42;
+}
+
+int main (void)
+{
+ volatile unsigned char *ptr = __builtin_alloca (15);
+
+ setHandler();
+
+ use (ptr);
+ ptr[0x10] = 0x55;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/texec-3.c
b/gcc/testsuite/gcc.target/aarch64/memtag/texec-3.c
new file mode 100644
index 00000000000..490f5878ddf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/texec-3.c
@@ -0,0 +1,37 @@
+/* { dg-do run { xfail *-*-* } } */
+/* { dg-require-effective-target memtag_exec } */
+/* { dg-require-effective-target pthread } */
+/* { dg-additional-options "-O2 -pthread" } */
+#include "mte-sig.h"
+#include <pthread.h>
+
+void __attribute__((noinline))
+use (volatile unsigned char *ptr)
+{
+ ptr[0] = 0x41;
+ ptr[1] = 0x42;
+}
+
+/* The thread in which we allocate and then we try to read out of the
+ allocation pool. */
+void *thread_test (void *)
+{
+ volatile unsigned char *ptr = __builtin_alloca (15);
+
+ setHandler();
+
+ use (ptr);
+ ptr[0x10] = 0x55;
+ return 0;
+}
+
+
+int main (void)
+{
+ pthread_t thread;
+ pthread_create (&thread, NULL, thread_test, NULL);
+ pthread_join (thread, NULL);
+ __builtin_printf ("End of line\n");
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/value-init.c
b/gcc/testsuite/gcc.target/aarch64/memtag/value-init.c
new file mode 100644
index 00000000000..7f2c9d3123e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/value-init.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+void use (int *);
+
+void foo (void)
+{
+ int x = 42;
+ use(&x);
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {stg\t...?, \[sp, 16\]\n} 2 } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/vararray-gimple.c
b/gcc/testsuite/gcc.target/aarch64/memtag/vararray-gimple.c
new file mode 100644
index 00000000000..302964d277b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/vararray-gimple.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-asan -O2" } */
+
+extern int *use (int *b, int n);
+
+int *foo (int n)
+{
+ int b[n];
+ return use (b, n);
+}
+
+/* HWASAN_ALLOCA_POISON is used for alloca and VLAs when MEMTAG is in effect.
+ Although HWASAN_ALLOCA_UNPOISON is (also) used for untagging frame, it
+ doesnt hurt to check it in context of the current test. */
+/* { dg-final { scan-tree-dump "HWASAN_ALLOCA_POISON" "asan1" } } */
+/* { dg-final { scan-tree-dump "HWASAN_ALLOCA_UNPOISON" "asan1" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/vararray.c
b/gcc/testsuite/gcc.target/aarch64/memtag/vararray.c
new file mode 100644
index 00000000000..a01a5cd8a8b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/vararray.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+extern int *use (int *b, int n);
+
+int *foo (int n)
+{
+ int b[n];
+ return use (b, n);
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {stg\t...?, \[...?\], 16\n} 3 } } */
+/* { dg-final { scan-assembler-times {\taddg\t} 0 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/vla-1.c
b/gcc/testsuite/gcc.target/aarch64/memtag/vla-1.c
new file mode 100644
index 00000000000..1ad74fe67d5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/vla-1.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-require-effective-target memtag_exec } */
+/* { dg-additional-options "-O2" } */
+
+#include <string.h>
+#include "mte-sig.h"
+
+void
+bar (int i, char *b)
+{
+ __builtin_printf ("i = %d, b+i = %s \n", i, b + i);
+}
+
+void
+foo (int size)
+{
+ int i;
+ for (i = 0; i < size; i++)
+ {
+ char temp[size];
+ memset (temp, 'B', size);
+ temp[size-1] = '\0';
+ {
+ char temp2[size];
+ memset (temp2, 'A', size);
+ temp2[size-1] = '\0';
+ bar (i, temp2);
+ }
+ bar (i, temp);
+ }
+}
+
+int main (void)
+{
+ setHandler ();
+ foo (10);
+ foo (3);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/vla-2.c
b/gcc/testsuite/gcc.target/aarch64/memtag/vla-2.c
new file mode 100644
index 00000000000..526306a5e60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/vla-2.c
@@ -0,0 +1,48 @@
+
+/* { dg-do run { xfail *-*-* } } */
+/* { dg-require-effective-target memtag_exec } */
+/* { dg-additional-options "-O2" } */
+
+#include "mte-sig.h"
+
+/* Testing that a function with outgoing arguments correctly decrements the
+ stack pointer when a vararray goes out of scope. */
+
+const char * __attribute__((noinline))
+other (int argc, int a, int b, int c, int d, int e, int f,
+ int g, int h, int i, int j, int k, int l)
+{
+ const char ** other;
+ {
+ const char * test_array[argc];
+ test_array[0] = "test string";
+ test_array[argc - 1] = "hello";
+ /* To prevent optimisation. */
+ __builtin_printf ("While the value stored in our test_array is: %s\n",
+ test_array[argc - 1]);
+ other = test_array;
+ }
+ /* With the below function call (the one with many arguments), some of the
+ arguments have to be put on the stack, which means we have to reserve some
+ space on the stack for these arguments and that the VLA is stored at a
+ position that is not the stack pointer. */
+ __builtin_printf ("Our numbers today are: %d, %d, %d, %d, %d, %d, %d, %d, \
+%d, %d, %d, %d\n",
+ a, b, c, d, e, f, g, h, i, j, k, l);
+ /* This should fail due to a bad read access. */
+ return other[0];
+}
+
+int
+main (void)
+{
+ int a, b, c, d, e, f, g, h, i, j, k, l;
+
+ setHandler();
+ const char * retval = other (1, a, b, c, d, e, f, g, h, i, j, k, l);
+ /* Numbers don't matter here, just want to ensure the program is reading them
+ so we know they won't be optimised out. */
+ if (retval)
+ return 1;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/zero-init.c
b/gcc/testsuite/gcc.target/aarch64/memtag/zero-init.c
new file mode 100644
index 00000000000..75980e8d430
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/zero-init.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+void use (int *);
+
+void foo (void)
+{
+ int x = 0;
+ use (&x);
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {stg\t...?, \[sp, 16\]\n} 2 } } */
+
diff --git a/gcc/testsuite/lib/target-supports.exp
b/gcc/testsuite/lib/target-supports.exp
index 1acfb373beb..072a195d1d1 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -4986,6 +4986,17 @@ proc check_effective_target_aarch64_sve1_only { } {
&& ![check_effective_target_aarch64_sve2] }]
}
+# Return 1 if this is an AArch64 target supporting MTE.
+proc check_effective_target_aarch64_mte { } {
+ if { ![istarget aarch64*-*-*] } {
+ return 0
+ }
+ return [check_no_compiler_messages aarch64_mte assembly {
+ #if !defined (__ARM_FEATURE_MEMORY_TAGGING)
+ #error FOO
+ #endif
+ } "-march=armv8.5-a+memtag"]
+}
# Return the size in bits of an SVE vector, or 0 if the size is variable.
proc aarch64_sve_bits { } {
return [check_cached_effective_target aarch64_sve_bits {
@@ -14674,3 +14685,35 @@ proc check_effective_target_fentry { } {
}
}]
}
+
+# Return 1 if target can compile and run binary for stack
+# sanitization, 0 otherwise.
+proc check_effective_target_memtag_exec {} {
+ if ![check_runtime memtag_exec {
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ extern int prctl(int, unsigned long, unsigned long, unsigned long,
unsigned long);
+ #ifdef __cplusplus
+ }
+ #endif
+ int main (void) {
+ #define PR_SET_TAGGED_ADDR_CTRL 55
+ #define PR_GET_TAGGED_ADDR_CTRL 56
+ #define PR_TAGGED_ADDR_ENABLE (1UL << 0)
+ #define PR_MTE_TCF_SYNC (1UL << 1)
+ #define PR_MTE_TAG_SHIFT 3
+ if (prctl (PR_GET_TAGGED_ADDR_CTRL, 0,0,0,0) == -1)
+ return -1;
+ if (prctl (PR_SET_TAGGED_ADDR_CTRL,
+ PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC
+ | (0xfffe << PR_MTE_TAG_SHIFT), 0, 0, 0) == -1
+ || !prctl (PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0))
+ return 1;
+ return 0;
+ }
+ }] {
+ return 0;
+ }
+ return 1;
+}
--
2.51.0