/* ==================================================================== * Copyright (c) 2005 The OpenSSL Project. Rights for redistribution * and usage in source and binary forms are granted according to the * OpenSSL license. */ #include #if defined(__DECC) # include # pragma __nostandard #endif #include "e_os.h" #if !defined(POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION) # if (defined(__sun) && (defined(__sparc) || defined(__sparcv9))) || \ (defined(__sgi) && (defined(__mips) || defined(mips))) || \ (defined(__osf__) && defined(__alpha)) || \ (defined(__linux) && (defined(__arm) || defined(__arm__))) || \ (defined(__i386) || defined(__i386__)) || \ (defined(__x86_64) || defined(__x86_64__)) || \ defined(__ANDROID__) || \ (defined(vax) || defined(__vax__)) # define POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION # endif #endif #if defined(__xlC__) && __xlC__>=0x600 && (defined(_POWER) || defined(_ARCH_PPC)) static void *instruction_pointer_xlc(void); # pragma mc_func instruction_pointer_xlc {\ "7c0802a6" /* mflr r0 */ \ "48000005" /* bl $+4 */ \ "7c6802a6" /* mflr r3 */ \ "7c0803a6" /* mtlr r0 */ } # pragma reg_killed_by instruction_pointer_xlc gr0 gr3 # define INSTRUCTION_POINTER_IMPLEMENTED(ret) (ret=instruction_pointer_xlc()); #endif #ifdef FIPS_START # define FIPS_ref_point FIPS_text_start /* * Some compilers put string literals into a separate segment. As we are * mostly interested to hash AES tables in .rodata, we declare reference * points accordingly. In case you wonder, the values are big-endian encoded * variable names, just to prevent these arrays from being merged by linker. */ const unsigned int FIPS_rodata_start[] = { 0x46495053, 0x5f726f64, 0x6174615f, 0x73746172 }; #else # define FIPS_ref_point FIPS_text_end const unsigned int FIPS_rodata_end[] = { 0x46495053, 0x5f726f64, 0x6174615f, 0x656e645b }; #endif /* * I declare reference function as static in order to avoid certain * pitfalls in -dynamic linker behaviour... */ static void *instruction_pointer(void) { void *ret = NULL; /* * These are ABI-neutral CPU-specific snippets. ABI-neutrality means that * they are designed to work under any OS running on particular CPU, * which is why you don't find any #ifdef THIS_OR_THAT_OS in this * function. */ #if defined(INSTRUCTION_POINTER_IMPLEMENTED) INSTRUCTION_POINTER_IMPLEMENTED(ret); #elif defined(__GNUC__) && __GNUC__>=2 # if defined(__alpha) || defined(__alpha__) # define INSTRUCTION_POINTER_IMPLEMENTED __asm __volatile("br %0,1f\n1:":"=r"(ret)); # elif defined(__i386) || defined(__i386__) # define INSTRUCTION_POINTER_IMPLEMENTED __asm __volatile("call 1f\n1: popl %0":"=r"(ret)); ret = (void *)((size_t)ret & ~3UL); /* align for better performance */ # elif defined(__ia64) || defined(__ia64__) # define INSTRUCTION_POINTER_IMPLEMENTED __asm __volatile("mov %0=ip":"=r"(ret)); # elif defined(__hppa) || defined(__hppa__) || defined(__pa_risc) # define INSTRUCTION_POINTER_IMPLEMENTED __asm __volatile("blr %%r0,%0\n\tnop":"=r"(ret)); ret = (void *)((size_t)ret & ~3UL); /* mask privilege level */ # elif defined(__mips) || defined(__mips__) # define INSTRUCTION_POINTER_IMPLEMENTED void *scratch; __asm __volatile("move %1,$31\n\t" /* save ra */ "bal .+8; nop\n\t" "move %0,$31\n\t" /* restore ra */ "move $31,%1":"=r"(ret), "=r"(scratch)); # elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || \ defined(__POWERPC__) || defined(_POWER) || defined(__PPC__) || \ defined(__PPC64__) || defined(__powerpc64__) # define INSTRUCTION_POINTER_IMPLEMENTED void *scratch; __asm __volatile("mfspr %1,8\n\t" /* save lr */ "bl $+4\n\t" "mfspr %0,8\n\t" /* mflr ret */ "mtspr 8,%1" /* restore lr */ :"=r"(ret), "=r"(scratch)); # elif defined(__s390__) || defined(__s390x__) # define INSTRUCTION_POINTER_IMPLEMENTED __asm __volatile("bras %0,1f\n1:":"=r"(ret)); ret = (void *)((size_t)ret & ~3UL); # elif defined(__sparc) || defined(__sparc__) || defined(__sparcv9) # define INSTRUCTION_POINTER_IMPLEMENTED void *scratch; __asm __volatile("mov %%o7,%1\n\t" "call .+8; nop\n\t" "mov %%o7,%0\n\t" "mov %1,%%o7":"=r"(ret), "=r"(scratch)); # elif defined(__x86_64) || defined(__x86_64__) # define INSTRUCTION_POINTER_IMPLEMENTED __asm __volatile("leaq 0(%%rip),%0":"=r"(ret)); ret = (void *)((size_t)ret & ~3UL); /* align for better performance */ # endif #elif defined(__DECC) && defined(__alpha) # define INSTRUCTION_POINTER_IMPLEMENTED ret = (void *)(size_t)asm("br %v0,1f\n1:"); #elif defined(_MSC_VER) && defined(_M_IX86) # define INSTRUCTION_POINTER_IMPLEMENTED void *scratch; _asm { call self self:pop eax mov scratch, eax} ret = (void *)((size_t)scratch & ~3UL); #endif return ret; } /* * This function returns pointer to an instruction in the vicinity of * its entry point, but not outside this object module. This guarantees * that sequestered code is covered... */ void *FIPS_ref_point() { #if defined(INSTRUCTION_POINTER_IMPLEMENTED) return instruction_pointer(); /* * Below we essentially cover vendor compilers which do not support * inline assembler... */ #elif defined(_AIX) struct { void *ip, *gp, *env; } *p = (void *)instruction_pointer; return p->ip; #elif defined(_HPUX_SOURCE) # if defined(__hppa) || defined(__hppa__) struct { void *i[4]; } *p = (void *)FIPS_ref_point; if (sizeof(p) == 8) /* 64-bit */ return p->i[2]; else if ((size_t)p & 2) { p = (void *)((size_t)p & ~3UL); return p->i[0]; } else return (void *)p; # elif defined(__ia64) || defined(__ia64__) struct { unsigned long long ip, gp; } *p = (void *)instruction_pointer; return (void *)(size_t)p->ip; # endif #elif (defined(__VMS) || defined(VMS)) && !(defined(vax) || defined(__vax__)) /* applies to both alpha and ia64 */ struct { unsigned __int64 opaque, ip; } *p = (void *)instruction_pointer; return (void *)(size_t)p->ip; #elif defined(__VOS__) /* applies to both pa-risc and ia32 */ struct { void *dp, *ip, *gp; } *p = (void *)instruction_pointer; return p->ip; #elif defined(_WIN32) # if defined(_WIN64) && defined(_M_IA64) struct { void *ip, *gp; } *p = (void *)FIPS_ref_point; return p->ip; # else return (void *)FIPS_ref_point; # endif /* * In case you wonder why there is no #ifdef __linux. All Linux targets * are GCC-based and therefore are covered by instruction_pointer above * [well, some are covered by by the one below]... */ #elif defined(POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION) return (void *)instruction_pointer; #else return NULL; #endif }