|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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; |
|
|
} |
|
|
|