| /* ==================================================================== |
| * Copyright (c) 2005 The OpenSSL Project. Rights for redistribution |
| * and usage in source and binary forms are granted according to the |
| * OpenSSL license. |
| */ |
| |
| #include <stdio.h> |
| #if defined(__DECC) |
| # include <c_asm.h> |
| # pragma __nostandard |
| #endif |
| |
| const void *FIPS_text_start(void); |
| const void *FIPS_text_end(void); |
| |
| #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(vax) || defined(__vax__)) |
| # define POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION |
| # endif |
| #endif |
| |
| #if !defined(FIPS_REF_POINT_IS_CROSS_COMPILER_AWARE) |
| # if (defined(__ANDROID__) && (defined(__arm__) || defined(__arm) || \ |
| defined(__i386__)|| defined(__i386))) || \ |
| (defined(__vxworks) && (defined(__ppc__) || defined(__ppc) || \ |
| defined(__mips__)|| defined(__mips))) || \ |
| (defined(__linux) && ((defined(__PPC__) && !defined(__PPC64__)) || \ |
| defined(__arm__) || defined(__arm))) || \ |
| (defined(__APPLE__) /* verified on all MacOS X & iOS flavors */)|| \ |
| (defined(_WIN32) && defined(_MSC_VER)) |
| # define FIPS_REF_POINT_IS_CROSS_COMPILER_AWARE |
| # 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 |
| # ifdef FIPS_REF_POINT_IS_CROSS_COMPILER_AWARE |
| # define instruction_pointer FIPS_text_startX |
| # endif |
| /* 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. */ |
| # if defined(_MSC_VER) |
| # pragma code_seg("fipstx") |
| # pragma code_seg() |
| __declspec(allocate("fipstx")) |
| const unsigned int FIPS_text_startX[]= |
| { 0x46495053, 0x5f746578, 0x745f7374, 0x61727458 }; |
| # pragma const_seg("fipsro$a") |
| # pragma const_seg() |
| __declspec(allocate("fipsro$a")) |
| # endif |
| const unsigned int FIPS_rodata_start[]= |
| { 0x46495053, 0x5f726f64, 0x6174615f, 0x73746172 }; |
| #else |
| # define FIPS_ref_point FIPS_text_end |
| # ifdef FIPS_REF_POINT_IS_CROSS_COMPILER_AWARE |
| # define instruction_pointer FIPS_text_endX |
| # endif |
| # if defined(_MSC_VER) |
| # pragma code_seg("fipstx$z") |
| # pragma code_seg() |
| __declspec(allocate("fipstx$z")) |
| const unsigned int FIPS_text_endX[]= |
| { 0x46495053, 0x5f746578, 0x745f656e, 0x64585b5d }; |
| # pragma const_seg("fipsro$z") |
| # pragma const_seg() |
| __declspec(allocate("fipsro$z")) |
| # endif |
| const unsigned int FIPS_rodata_end[]= |
| { 0x46495053, 0x5f726f64, 0x6174615f, 0x656e645b }; |
| #endif |
| |
| #if !defined(_MSC_VER) || !defined(instruction_pointer) |
| /* |
| * 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" |
| "move $31,%1" /* restore ra */ |
| : "=r"(ret),"=r"(scratch) ); |
| # elif defined(__ppc__) || defined(__ppc) || \ |
| defined(__powerpc) || defined(__powerpc__) || \ |
| defined(__POWERPC__) || defined(_POWER) || defined(__PPC__) || \ |
| defined(__PPC64__) || 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 */ |
| # elif defined(__arm) || defined(__arm__) |
| # define INSTRUCTION_POINTER_IMPLEMENTED |
| __asm __volatile ( "sub %0,pc,#8" : "=r"(ret) ); |
| # 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; |
| } |
| #endif |
| |
| /* |
| * 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... |
| */ |
| const void *FIPS_ref_point() |
| { |
| #if defined(FIPS_REF_POINT_IS_CROSS_COMPILER_AWARE) |
| # if defined(__thumb__) || defined(__thumb) |
| return (void *)((size_t)instruction_pointer&~1); |
| # else |
| return (void *)instruction_pointer; |
| # endif |
| #elif 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 |
| } |