| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include <config.h> |
|
|
| |
| #include <jit/cache.h> |
|
|
| #include <fcntl.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
|
|
| #if HAVE_SYS_MMAN_H |
| # include <sys/mman.h> |
| #endif |
|
|
| #if defined __APPLE__ && defined __MACH__ |
| # define KEEP_TEMP_FILE_VISIBLE |
| |
| # include "clean-temp-simple.h" |
| #endif |
|
|
| #include "xalloc.h" |
| #include "macros.h" |
|
|
| |
| |
| |
| |
| |
| |
| #if defined __clang__ && __clang_major__ >= 17 && defined __ELF__ |
| # include <dlfcn.h> |
| #endif |
| static int clang_ubsan_workaround = 0; |
|
|
| |
| |
| |
| |
|
|
| #if ((defined __powerpc__ || defined __powerpc64__) && defined _AIX) || (defined __powerpc64__ && !defined __powerpc64_elfv2__ && defined __linux__) |
| struct func |
| { |
| void *code_address; |
| void *toc_pointer; |
| void *static_chain; |
| }; |
| #elif defined __ia64__ |
| # if defined __ia64_ilp32__ |
| struct func |
| { |
| void *code_address; |
| void *unused1; |
| void *global_pointer; |
| void *unused2; |
| }; |
| # else |
| struct func |
| { |
| void *code_address; |
| void *global_pointer; |
| }; |
| # endif |
| #elif defined __hppa__ |
| # if defined __hppa64__ |
| struct func |
| { |
| void *some_other_code_address; |
| void *some_other_pic_base; |
| void *code_address; |
| void *pic_base; |
| }; |
| # else |
| struct func |
| { |
| void *code_address; |
| void *pic_base; |
| }; |
| # define FUNCPTR_BIAS 2 |
| # endif |
| #else |
| # define FUNCPTR_POINTS_TO_CODE |
| #endif |
| #ifdef FUNCPTR_POINTS_TO_CODE |
| |
| # define COPY_FUNCPTR(funcptr) funcptr |
| |
| |
| # if defined __arm__ || defined __armhf__ |
| # define CODE(funcptr) ((void *) ((uintptr_t) (funcptr) & ~(intptr_t)1)) |
| # define SET_CODE(funcptr,code_addr) \ |
| ((void) ((funcptr) = \ |
| (void *) (((uintptr_t) (funcptr) & (intptr_t)1) \ |
| | (uintptr_t) (code_addr)))) |
| # define IS(funcptr) ((uintptr_t) (funcptr) & 1) |
| # define SET_IS(funcptr,is) \ |
| ((void) ((funcptr) = \ |
| (void *) (((uintptr_t) (funcptr) & ~(intptr_t)1) | (is)))) |
| # else |
| # define CODE(funcptr) ((char *) (funcptr) - clang_ubsan_workaround) |
| # define SET_CODE(funcptr,code_addr) \ |
| ((void) ((funcptr) = (void *) ((char *) (code_addr) + clang_ubsan_workaround))) |
| # define IS(funcptr) ((void) (funcptr), 0) |
| # define SET_IS(funcptr,is) ((void) (funcptr), (void) (is)) |
| # endif |
| #else |
| |
| # if FUNCPTR_BIAS |
| static inline void * |
| structptr_to_funcptr (struct func *p) |
| { |
| return (char *) p + FUNCPTR_BIAS; |
| } |
| static inline struct func * |
| funcptr_to_structptr (void * volatile funcptr) |
| { |
| return (struct func *) ((char *) funcptr - FUNCPTR_BIAS); |
| } |
| # else |
| # define structptr_to_funcptr(p) ((void *) (p)) |
| static inline struct func * |
| funcptr_to_structptr (void * volatile funcptr) |
| { |
| return (struct func *) funcptr; |
| } |
| # endif |
| static inline struct func * |
| xcopy_structptr (struct func *structptr) |
| { |
| struct func *copy = (struct func *) xmalloc (sizeof (struct func)); |
| *copy = *structptr; |
| return copy; |
| } |
| # define COPY_FUNCPTR(funcptr) \ |
| structptr_to_funcptr (xcopy_structptr (funcptr_to_structptr (funcptr))) |
| # define CODE(funcptr) \ |
| ((funcptr_to_structptr (funcptr))->code_address) |
| # define SET_CODE(funcptr,code_addr) \ |
| ((void) (CODE (funcptr) = (code_addr))) |
| # define IS(funcptr) ((void) (funcptr), 0) |
| # define SET_IS(funcptr,is) ((void) (funcptr), (void) (is)) |
| #endif |
|
|
| |
| |
| |
|
|
| static int |
| return1 (void) |
| { |
| return 1; |
| } |
|
|
| static int |
| return2 (void) |
| { |
| return 2; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| #if defined __x86_64__ || defined __x86_64_x32__ || defined __i386__ |
| unsigned char const return1_code[] = { 0xb8,0x01,0x00,0x00,0x00, 0xc3 }; |
| unsigned char const return2_code[] = { 0xb8,0x02,0x00,0x00,0x00, 0xc3 }; |
| #endif |
| #if defined __alpha__ |
| unsigned int const return1_code[] = { 0x201f0001, 0x6bfa8001 }; |
| unsigned int const return2_code[] = { 0x201f0002, 0x6bfa8001 }; |
| #endif |
| #if defined __arm64__ || defined __arm64_ilp32__ |
| unsigned int const return1_code[] = { 0x52800020, 0xd65f03c0 }; |
| unsigned int const return2_code[] = { 0x52800040, 0xd65f03c0 }; |
| #elif defined __arm__ || defined __armhf__ |
| unsigned int const return1_code[] = { 0xe3a00001, 0xe1a0f00e }; |
| unsigned int const return2_code[] = { 0xe3a00002, 0xe1a0f00e }; |
| #endif |
| #if defined __hppa64__ |
| unsigned int const return1_code[] = { 0xe840d000, 0x341c0002 }; |
| unsigned int const return2_code[] = { 0xe840d000, 0x341c0004 }; |
| #elif defined __hppa__ |
| unsigned int const return1_code[] = { 0xe840c000, 0x341c0002 }; |
| unsigned int const return2_code[] = { 0xe840c000, 0x341c0004 }; |
| #endif |
| #if defined __ia64__ || defined __ia64_ilp32__ |
| unsigned char const return1_code[] = |
| { 0x11,0x00,0x00,0x00,0x01,0x00,0x80,0x08,0x00,0x00,0x48,0x80,0x08,0x00,0x84,0x00 }; |
| unsigned char const return2_code[] = |
| { 0x11,0x00,0x00,0x00,0x01,0x00,0x80,0x10,0x00,0x00,0x48,0x80,0x08,0x00,0x84,0x00 }; |
| #endif |
| #if defined __loongarch64__ |
| unsigned int const return1_code[] = { 0x02800404, 0x4c000020 }; |
| unsigned int const return2_code[] = { 0x02800804, 0x4c000020 }; |
| #endif |
| #if defined __m68k__ |
| unsigned short const return1_code[] = { 0x7001, 0x4e75 }; |
| unsigned short const return2_code[] = { 0x7002, 0x4e75 }; |
| #endif |
| #if defined __mips64__ || defined __mipsn32__ || defined __mips__ |
| unsigned int const return1_code[] = { 0x03e00008, 0x24020001 }; |
| unsigned int const return2_code[] = { 0x03e00008, 0x24020002}; |
| #endif |
| #if defined __powerpc64__ || defined __powerpc64_elfv2__ || defined __powerpc__ |
| unsigned int const return1_code[] = { 0x38600001, 0x4e800020 }; |
| unsigned int const return2_code[] = { 0x38600002, 0x4e800020 }; |
| #endif |
| #if defined __riscv64__ || defined __riscv32__ |
| unsigned short const return1_code[] = { 0x4505, 0x8082 }; |
| unsigned short const return2_code[] = { 0x4509, 0x8082 }; |
| #endif |
| #if defined __s390x__ |
| unsigned short const return1_code[] = { 0xa729,0x0001, 0x07fe, 0x0707 }; |
| unsigned short const return2_code[] = { 0xa729,0x0002, 0x07fe, 0x0707 }; |
| #elif defined __s390__ |
| unsigned short const return1_code[] = { 0xa728,0x0001, 0x07fe, 0x0707 }; |
| unsigned short const return2_code[] = { 0xa728,0x0002, 0x07fe, 0x0707 }; |
| #endif |
| #if defined __sparc64__ || defined __sparc__ |
| unsigned int const return1_code[] = { 0x81c3e008, 0x90102001 }; |
| unsigned int const return2_code[] = { 0x81c3e008, 0x90102002 }; |
| #endif |
|
|
| int |
| main () |
| { |
| #if defined __clang__ && __clang_major__ >= 17 && defined __ELF__ |
| if (dlsym (RTLD_DEFAULT, "__ubsan_handle_function_type_mismatch") != NULL) |
| |
| clang_ubsan_workaround = 8; |
| #endif |
|
|
| void const *code_of_return1; |
| void const *code_of_return2; |
| size_t size_of_return1; |
| size_t size_of_return2; |
| int is_of_return1; |
| int is_of_return2; |
| #if defined __OpenBSD__ || defined _RET_PROTECTOR |
| |
| |
| |
| |
| |
| |
| |
| code_of_return1 = return1_code; |
| code_of_return2 = return2_code; |
| size_of_return1 = sizeof (return1_code); |
| size_of_return2 = sizeof (return2_code); |
| |
| is_of_return1 = 0; |
| is_of_return2 = 0; |
| #else |
| code_of_return1 = CODE (return1); |
| code_of_return2 = CODE (return2); |
| |
| size_of_return1 = 64; |
| size_of_return2 = 64; |
| is_of_return1 = IS (return1); |
| is_of_return2 = IS (return2); |
| #endif |
|
|
| int const pagesize = getpagesize (); |
| int const mapping_size = 1 * pagesize; |
| |
| char *start; |
| char *end; |
| |
| char *start_rw; |
|
|
| |
| { |
| #if defined _WIN32 && !defined __CYGWIN__ |
| |
| |
| |
| start = VirtualAlloc (NULL, mapping_size, MEM_COMMIT, |
| PAGE_EXECUTE_READWRITE); |
| if (start == NULL) |
| return 1; |
| start_rw = start; |
| #else |
| start = mmap (NULL, mapping_size, PROT_READ | PROT_WRITE | PROT_EXEC, |
| MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); |
| if (start != (char *) (-1)) |
| { |
| |
| |
| start_rw = start; |
| } |
| else |
| { |
| |
| |
| fprintf (stderr, "simple mmap failed, using separate mappings\n"); |
| char filename[100]; |
| sprintf (filename, |
| "%s/gnulib-test-cache-%u-%d-%ld", |
| "/tmp", (unsigned int) getuid (), (int) getpid (), random ()); |
| # ifdef KEEP_TEMP_FILE_VISIBLE |
| if (register_temporary_file (filename) < 0) |
| return 2; |
| # endif |
| int fd = open (filename, O_CREAT | O_RDWR | O_TRUNC, 0700); |
| if (fd < 0) |
| return 3; |
| # ifndef KEEP_TEMP_FILE_VISIBLE |
| |
| |
| |
| |
| unlink (filename); |
| # endif |
| if (ftruncate (fd, mapping_size) < 0) |
| return 4; |
| start = mmap (NULL, mapping_size, PROT_READ | PROT_EXEC, MAP_SHARED, |
| fd, 0); |
| start_rw = mmap (NULL, mapping_size, PROT_READ | PROT_WRITE, MAP_SHARED, |
| fd, 0); |
| if (start == (char *) (-1) || start_rw == (char *) (-1)) |
| return 5; |
| } |
| #endif |
| end = start + mapping_size; |
| } |
|
|
| int (*f) (void) = COPY_FUNCPTR (return1); |
| SET_CODE (f, start); |
|
|
| memcpy (start_rw, code_of_return1, size_of_return1); |
| SET_IS (f, is_of_return1); |
| clear_cache (start, end); |
| ASSERT (f () == 1); |
|
|
| memcpy (start_rw, code_of_return2, size_of_return2); |
| SET_IS (f, is_of_return2); |
| clear_cache (start, end); |
| ASSERT (f () == 2); |
|
|
| return test_exit_status; |
| } |
|
|