1 // REQUIRES: native-run
2 // UNSUPPORTED: arm, aarch64
3 // RUN: %clang_builtins %s %librt -o %t && %run %t
4 //===-- clear_cache_test.c - Test clear_cache -----------------------------===//
5 //
6 //                     The LLVM Compiler Infrastructure
7 //
8 // This file is dual licensed under the MIT and the University of Illinois Open
9 // Source Licenses. See LICENSE.TXT for details.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdint.h>
17 #if defined(_WIN32)
18 #include <windows.h>
19 static uintptr_t get_page_size() {
20     SYSTEM_INFO si;
21     GetSystemInfo(&si);
22     return si.dwPageSize;
23 }
24 #else
25 #include <unistd.h>
26 #include <sys/mman.h>
27 
28 static uintptr_t get_page_size() {
29     return sysconf(_SC_PAGE_SIZE);
30 }
31 #endif
32 
33 extern void __clear_cache(void* start, void* end);
34 
35 
36 typedef int (*pfunc)(void);
37 
38 // Make these static to avoid ILT jumps for incremental linking on Windows.
39 static int func1() { return 1; }
40 static int func2() { return 2; }
41 
42 void *__attribute__((noinline))
43 memcpy_f(void *dst, const void *src, size_t n) {
44 // ARM and MIPS nartually align functions, but use the LSB for ISA selection
45 // (THUMB, MIPS16/uMIPS respectively).  Ensure that the ISA bit is ignored in
46 // the memcpy
47 #if defined(__arm__) || defined(__mips__)
48   return (void *)((uintptr_t)memcpy(dst, (void *)((uintptr_t)src & ~1), n) |
49                   ((uintptr_t)src & 1));
50 #else
51   return memcpy(dst, (void *)((uintptr_t)src), n);
52 #endif
53 }
54 
55 unsigned char execution_buffer[128];
56 
57 int main()
58 {
59     // make executable the page containing execution_buffer
60     uintptr_t page_size = get_page_size();
61     char* start = (char*)((uintptr_t)execution_buffer & (-page_size));
62     char* end = (char*)((uintptr_t)(&execution_buffer[128+page_size]) & (-page_size));
63 #if defined(_WIN32)
64     DWORD dummy_oldProt;
65     MEMORY_BASIC_INFORMATION b;
66     if (!VirtualQuery(start, &b, sizeof(b)))
67         return 1;
68     if (!VirtualProtect(b.BaseAddress, b.RegionSize, PAGE_EXECUTE_READWRITE, &b.Protect))
69 #else
70     if (mprotect(start, end-start, PROT_READ|PROT_WRITE|PROT_EXEC) != 0)
71 #endif
72         return 1;
73 
74     // verify you can copy and execute a function
75     pfunc f1 = (pfunc)memcpy_f(execution_buffer, func1, 128);
76     __clear_cache(execution_buffer, &execution_buffer[128]);
77     if ((*f1)() != 1)
78         return 1;
79 
80     // verify you can overwrite a function with another
81     pfunc f2 = (pfunc)memcpy_f(execution_buffer, func2, 128);
82     __clear_cache(execution_buffer, &execution_buffer[128]);
83     if ((*f2)() != 2)
84         return 1;
85 
86     return 0;
87 }
88