/* * To be compiled with -march=armv8.5-a+memtag * * This test is adapted from a Linux test. Please see: * * https://www.kernel.org/doc/html/next/arch/arm64/memory-tagging-extension.html#example-of-correct-usage */ #include #include #include #include #include #include #include #include #include /* * From arch/arm64/include/uapi/asm/hwcap.h */ #define HWCAP2_MTE (1 << 18) /* * From arch/arm64/include/uapi/asm/mman.h */ #define PROT_MTE 0x20 /* * Insert a random logical tag into the given pointer. */ #define insert_random_tag(ptr) ({ \ uint64_t __val; \ asm("irg %0, %1" : "=r" (__val) : "r" (ptr)); \ __val; \ }) /* * Set the allocation tag on the destination address. */ #define set_tag(tagged_addr) do { \ asm volatile("stg %0, [%0]" : : "r" (tagged_addr) : "memory"); \ } while (0) int main(int argc, char *argv[]) { unsigned char *a; unsigned long page_sz = sysconf(_SC_PAGESIZE); unsigned long hwcap2 = getauxval(AT_HWCAP2); /* check if MTE is present */ if (!(hwcap2 & HWCAP2_MTE)) { return EXIT_FAILURE; } /* * Enable the tagged address ABI, synchronous or asynchronous MTE * tag check faults (based on per-CPU preference) and allow all * non-zero tags in the randomly generated set. */ if (prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC | (0xfffe << PR_MTE_TAG_SHIFT), 0, 0, 0)) { perror("prctl() failed"); return EXIT_FAILURE; } a = mmap(0, page_sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (a == MAP_FAILED) { perror("mmap() failed"); return EXIT_FAILURE; } printf("a[] address is %p\n", a); /* * Enable MTE on the above anonymous mmap. The flag could be passed * directly to mmap() and skip this step. */ if (mprotect(a, page_sz, PROT_READ | PROT_WRITE | PROT_MTE)) { perror("mprotect() failed"); return EXIT_FAILURE; } /* access with the default tag (0) */ a[0] = 1; a[1] = 2; printf("a[0] = %hhu a[1] = %hhu\n", a[0], a[1]); /* set the logical and allocation tags */ a = (unsigned char *)insert_random_tag(a); set_tag(a); printf("%p\n", a); return 0; }