qemu/tests/tcg/aarch64/bti-2.c
<<
>>
Prefs
   1/*
   2 * Branch target identification, basic notskip cases.
   3 */
   4
   5#include <stdio.h>
   6#include <signal.h>
   7#include <string.h>
   8#include <unistd.h>
   9#include <sys/mman.h>
  10
  11#ifndef PROT_BTI
  12#define PROT_BTI  0x10
  13#endif
  14
  15static void skip2_sigill(int sig, siginfo_t *info, void *vuc)
  16{
  17    ucontext_t *uc = vuc;
  18    uc->uc_mcontext.pc += 8;
  19    uc->uc_mcontext.pstate = 1;
  20}
  21
  22#define NOP       "nop"
  23#define BTI_N     "hint #32"
  24#define BTI_C     "hint #34"
  25#define BTI_J     "hint #36"
  26#define BTI_JC    "hint #38"
  27
  28#define BTYPE_1(DEST)    \
  29    "mov x1, #1\n\t"     \
  30    "adr x16, 1f\n\t"    \
  31    "br x16\n"           \
  32"1: " DEST "\n\t"        \
  33    "mov x1, #0"
  34
  35#define BTYPE_2(DEST)    \
  36    "mov x1, #1\n\t"     \
  37    "adr x16, 1f\n\t"    \
  38    "blr x16\n"          \
  39"1: " DEST "\n\t"        \
  40    "mov x1, #0"
  41
  42#define BTYPE_3(DEST)    \
  43    "mov x1, #1\n\t"     \
  44    "adr x15, 1f\n\t"    \
  45    "br x15\n"           \
  46"1: " DEST "\n\t"        \
  47    "mov x1, #0"
  48
  49#define TEST(WHICH, DEST, EXPECT) \
  50    WHICH(DEST) "\n"              \
  51    ".if " #EXPECT "\n\t"         \
  52    "eor x1, x1," #EXPECT "\n"    \
  53    ".endif\n\t"                  \
  54    "add x0, x0, x1\n\t"
  55
  56asm("\n"
  57"test_begin:\n\t"
  58    BTI_C "\n\t"
  59    "mov x2, x30\n\t"
  60    "mov x0, #0\n\t"
  61
  62    TEST(BTYPE_1, NOP, 1)
  63    TEST(BTYPE_1, BTI_N, 1)
  64    TEST(BTYPE_1, BTI_C, 0)
  65    TEST(BTYPE_1, BTI_J, 0)
  66    TEST(BTYPE_1, BTI_JC, 0)
  67
  68    TEST(BTYPE_2, NOP, 1)
  69    TEST(BTYPE_2, BTI_N, 1)
  70    TEST(BTYPE_2, BTI_C, 0)
  71    TEST(BTYPE_2, BTI_J, 1)
  72    TEST(BTYPE_2, BTI_JC, 0)
  73
  74    TEST(BTYPE_3, NOP, 1)
  75    TEST(BTYPE_3, BTI_N, 1)
  76    TEST(BTYPE_3, BTI_C, 1)
  77    TEST(BTYPE_3, BTI_J, 0)
  78    TEST(BTYPE_3, BTI_JC, 0)
  79
  80    "ret x2\n"
  81"test_end:"
  82);
  83
  84int main()
  85{
  86    struct sigaction sa;
  87    void *tb, *te;
  88
  89    void *p = mmap(0, getpagesize(),
  90                   PROT_EXEC | PROT_READ | PROT_WRITE | PROT_BTI,
  91                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  92    if (p == MAP_FAILED) {
  93        perror("mmap");
  94        return 1;
  95    }
  96
  97    memset(&sa, 0, sizeof(sa));
  98    sa.sa_sigaction = skip2_sigill;
  99    sa.sa_flags = SA_SIGINFO;
 100    if (sigaction(SIGILL, &sa, NULL) < 0) {
 101        perror("sigaction");
 102        return 1;
 103    }
 104
 105    /*
 106     * ??? With "extern char test_begin[]", some compiler versions
 107     * will use :got references, and some linker versions will
 108     * resolve this reference to a static symbol incorrectly.
 109     * Bypass this error by using a pc-relative reference directly.
 110     */
 111    asm("adr %0, test_begin; adr %1, test_end" : "=r"(tb), "=r"(te));
 112
 113    memcpy(p, tb, te - tb);
 114
 115    return ((int (*)(void))p)();
 116}
 117