104 lines · c
1// REQUIRES: native-run2// UNSUPPORTED: target={{(arm|aarch64).*}}3// RUN: %clang_builtins %s %librt -o %t && %run %t4// REQUIRES: librt_has_clear_cache5 6#include <stdio.h>7#include <string.h>8#include <stdint.h>9 10#if defined(_WIN32)11#include <windows.h>12#else13#include <unistd.h>14#include <sys/mman.h>15#endif16 17extern void __clear_cache(void* start, void* end);18 19typedef int (*pfunc)(void);20 21// Make these static to avoid ILT jumps for incremental linking on Windows.22static int func1() { return 1; }23static int func2() { return 2; }24 25void __attribute__((noinline))26memcpy_f(void *dst, const void *src, size_t n) {27// ARM and MIPS naturally align functions, but use the LSB for ISA selection28// (THUMB, MIPS16/uMIPS respectively). Ensure that the ISA bit is ignored in29// the memcpy30#if defined(__arm__) || defined(__mips__)31 memcpy(dst, (void *)((uintptr_t)src & ~1), n);32#else33 memcpy(dst, (void *)((uintptr_t)src), n);34#endif35}36 37// Realign the 'dst' pointer as if it has been returned by memcpy() above.38// We need to split it because we're using two mappings for the same area.39void *__attribute__((noinline))40realign_f(void *dst, const void *src, size_t n) {41#if defined(__arm__) || defined(__mips__)42 return (void *)((uintptr_t)dst | ((uintptr_t)src & 1));43#else44 return dst;45#endif46}47 48int main()49{50 const int kSize = 128;51#if defined(__NetBSD__)52 // we need to create separate RW and RX mappings to satisfy MPROTECT53 uint8_t *write_buffer = mmap(0, kSize,54 PROT_MPROTECT(PROT_READ | PROT_WRITE |55 PROT_EXEC),56 MAP_ANON | MAP_PRIVATE, -1, 0);57 if (write_buffer == MAP_FAILED)58 return 1;59 uint8_t *execution_buffer = mremap(write_buffer, kSize, NULL, kSize,60 MAP_REMAPDUP);61 if (execution_buffer == MAP_FAILED)62 return 1;63 64 if (mprotect(write_buffer, kSize, PROT_READ | PROT_WRITE) == -1)65 return 1;66 if (mprotect(execution_buffer, kSize, PROT_READ | PROT_EXEC) == -1)67 return 1;68#elif !defined(_WIN32)69 uint8_t *execution_buffer = mmap(0, kSize,70 PROT_READ | PROT_WRITE | PROT_EXEC,71 MAP_ANON | MAP_PRIVATE, -1, 0);72 if (execution_buffer == MAP_FAILED)73 return 1;74 uint8_t *write_buffer = execution_buffer;75#else76 HANDLE mapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,77 PAGE_EXECUTE_READWRITE, 0, kSize, NULL);78 if (mapping == NULL)79 return 1;80 81 uint8_t* execution_buffer = MapViewOfFile(82 mapping, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, 0);83 if (execution_buffer == NULL)84 return 1;85 uint8_t *write_buffer = execution_buffer;86#endif87 88 // verify you can copy and execute a function89 memcpy_f(write_buffer, func1, kSize);90 pfunc f1 = (pfunc)realign_f(execution_buffer, func1, kSize);91 __clear_cache(execution_buffer, execution_buffer + kSize);92 if ((*f1)() != 1)93 return 1;94 95 // verify you can overwrite a function with another96 memcpy_f(write_buffer, func2, kSize);97 pfunc f2 = (pfunc)realign_f(execution_buffer, func2, kSize);98 __clear_cache(execution_buffer, execution_buffer + kSize);99 if ((*f2)() != 2)100 return 1;101 102 return 0;103}104