fips_canister.c revision 296465
1/* ==================================================================== 2 * Copyright (c) 2005 The OpenSSL Project. Rights for redistribution 3 * and usage in source and binary forms are granted according to the 4 * OpenSSL license. 5 */ 6 7#include <stdio.h> 8#if defined(__DECC) 9# include <c_asm.h> 10# pragma __nostandard 11#endif 12 13#include "e_os.h" 14 15#if !defined(POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION) 16# if (defined(__sun) && (defined(__sparc) || defined(__sparcv9))) || \ 17 (defined(__sgi) && (defined(__mips) || defined(mips))) || \ 18 (defined(__osf__) && defined(__alpha)) || \ 19 (defined(__linux) && (defined(__arm) || defined(__arm__))) || \ 20 (defined(__i386) || defined(__i386__)) || \ 21 (defined(__x86_64) || defined(__x86_64__)) || \ 22 defined(__ANDROID__) || \ 23 (defined(vax) || defined(__vax__)) 24# define POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION 25# endif 26#endif 27 28#if defined(__xlC__) && __xlC__>=0x600 && (defined(_POWER) || defined(_ARCH_PPC)) 29static void *instruction_pointer_xlc(void); 30# pragma mc_func instruction_pointer_xlc {\ 31 "7c0802a6" /* mflr r0 */ \ 32 "48000005" /* bl $+4 */ \ 33 "7c6802a6" /* mflr r3 */ \ 34 "7c0803a6" /* mtlr r0 */ } 35# pragma reg_killed_by instruction_pointer_xlc gr0 gr3 36# define INSTRUCTION_POINTER_IMPLEMENTED(ret) (ret=instruction_pointer_xlc()); 37#endif 38 39#ifdef FIPS_START 40# define FIPS_ref_point FIPS_text_start 41/* 42 * Some compilers put string literals into a separate segment. As we are 43 * mostly interested to hash AES tables in .rodata, we declare reference 44 * points accordingly. In case you wonder, the values are big-endian encoded 45 * variable names, just to prevent these arrays from being merged by linker. 46 */ 47const unsigned int FIPS_rodata_start[] = 48 { 0x46495053, 0x5f726f64, 0x6174615f, 0x73746172 }; 49#else 50# define FIPS_ref_point FIPS_text_end 51const unsigned int FIPS_rodata_end[] = 52 { 0x46495053, 0x5f726f64, 0x6174615f, 0x656e645b }; 53#endif 54 55/* 56 * I declare reference function as static in order to avoid certain 57 * pitfalls in -dynamic linker behaviour... 58 */ 59static void *instruction_pointer(void) 60{ 61 void *ret = NULL; 62 /* 63 * These are ABI-neutral CPU-specific snippets. ABI-neutrality means that 64 * they are designed to work under any OS running on particular CPU, 65 * which is why you don't find any #ifdef THIS_OR_THAT_OS in this 66 * function. 67 */ 68#if defined(INSTRUCTION_POINTER_IMPLEMENTED) 69 INSTRUCTION_POINTER_IMPLEMENTED(ret); 70#elif defined(__GNUC__) && __GNUC__>=2 71# if defined(__alpha) || defined(__alpha__) 72# define INSTRUCTION_POINTER_IMPLEMENTED 73 __asm __volatile("br %0,1f\n1:":"=r"(ret)); 74# elif defined(__i386) || defined(__i386__) 75# define INSTRUCTION_POINTER_IMPLEMENTED 76 __asm __volatile("call 1f\n1: popl %0":"=r"(ret)); 77 ret = (void *)((size_t)ret & ~3UL); /* align for better performance */ 78# elif defined(__ia64) || defined(__ia64__) 79# define INSTRUCTION_POINTER_IMPLEMENTED 80 __asm __volatile("mov %0=ip":"=r"(ret)); 81# elif defined(__hppa) || defined(__hppa__) || defined(__pa_risc) 82# define INSTRUCTION_POINTER_IMPLEMENTED 83 __asm __volatile("blr %%r0,%0\n\tnop":"=r"(ret)); 84 ret = (void *)((size_t)ret & ~3UL); /* mask privilege level */ 85# elif defined(__mips) || defined(__mips__) 86# define INSTRUCTION_POINTER_IMPLEMENTED 87 void *scratch; 88 __asm __volatile("move %1,$31\n\t" /* save ra */ 89 "bal .+8; nop\n\t" "move %0,$31\n\t" 90 /* restore ra */ 91 "move $31,%1":"=r"(ret), "=r"(scratch)); 92# elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || \ 93 defined(__POWERPC__) || defined(_POWER) || defined(__PPC__) || \ 94 defined(__PPC64__) || defined(__powerpc64__) 95# define INSTRUCTION_POINTER_IMPLEMENTED 96 void *scratch; 97 __asm __volatile("mfspr %1,8\n\t" /* save lr */ 98 "bl $+4\n\t" "mfspr %0,8\n\t" /* mflr ret */ 99 "mtspr 8,%1" /* restore lr */ 100 :"=r"(ret), "=r"(scratch)); 101# elif defined(__s390__) || defined(__s390x__) 102# define INSTRUCTION_POINTER_IMPLEMENTED 103 __asm __volatile("bras %0,1f\n1:":"=r"(ret)); 104 ret = (void *)((size_t)ret & ~3UL); 105# elif defined(__sparc) || defined(__sparc__) || defined(__sparcv9) 106# define INSTRUCTION_POINTER_IMPLEMENTED 107 void *scratch; 108 __asm __volatile("mov %%o7,%1\n\t" 109 "call .+8; nop\n\t" 110 "mov %%o7,%0\n\t" 111 "mov %1,%%o7":"=r"(ret), "=r"(scratch)); 112# elif defined(__x86_64) || defined(__x86_64__) 113# define INSTRUCTION_POINTER_IMPLEMENTED 114 __asm __volatile("leaq 0(%%rip),%0":"=r"(ret)); 115 ret = (void *)((size_t)ret & ~3UL); /* align for better performance */ 116# endif 117#elif defined(__DECC) && defined(__alpha) 118# define INSTRUCTION_POINTER_IMPLEMENTED 119 ret = (void *)(size_t)asm("br %v0,1f\n1:"); 120#elif defined(_MSC_VER) && defined(_M_IX86) 121# define INSTRUCTION_POINTER_IMPLEMENTED 122 void *scratch; 123 _asm { 124 call self 125 self:pop eax 126 mov scratch, eax} ret = (void *)((size_t)scratch & ~3UL); 127#endif 128 return ret; 129} 130 131/* 132 * This function returns pointer to an instruction in the vicinity of 133 * its entry point, but not outside this object module. This guarantees 134 * that sequestered code is covered... 135 */ 136void *FIPS_ref_point() 137{ 138#if defined(INSTRUCTION_POINTER_IMPLEMENTED) 139 return instruction_pointer(); 140 /* 141 * Below we essentially cover vendor compilers which do not support 142 * inline assembler... 143 */ 144#elif defined(_AIX) 145 struct { 146 void *ip, *gp, *env; 147 } *p = (void *)instruction_pointer; 148 return p->ip; 149#elif defined(_HPUX_SOURCE) 150# if defined(__hppa) || defined(__hppa__) 151 struct { 152 void *i[4]; 153 } *p = (void *)FIPS_ref_point; 154 155 if (sizeof(p) == 8) /* 64-bit */ 156 return p->i[2]; 157 else if ((size_t)p & 2) { 158 p = (void *)((size_t)p & ~3UL); 159 return p->i[0]; 160 } else 161 return (void *)p; 162# elif defined(__ia64) || defined(__ia64__) 163 struct { 164 unsigned long long ip, gp; 165 } *p = (void *)instruction_pointer; 166 return (void *)(size_t)p->ip; 167# endif 168#elif (defined(__VMS) || defined(VMS)) && !(defined(vax) || defined(__vax__)) 169 /* applies to both alpha and ia64 */ 170 struct { 171 unsigned __int64 opaque, ip; 172 } *p = (void *)instruction_pointer; 173 return (void *)(size_t)p->ip; 174#elif defined(__VOS__) 175 /* applies to both pa-risc and ia32 */ 176 struct { 177 void *dp, *ip, *gp; 178 } *p = (void *)instruction_pointer; 179 return p->ip; 180#elif defined(_WIN32) 181# if defined(_WIN64) && defined(_M_IA64) 182 struct { 183 void *ip, *gp; 184 } *p = (void *)FIPS_ref_point; 185 return p->ip; 186# else 187 return (void *)FIPS_ref_point; 188# endif 189 /* 190 * In case you wonder why there is no #ifdef __linux. All Linux targets 191 * are GCC-based and therefore are covered by instruction_pointer above 192 * [well, some are covered by by the one below]... 193 */ 194#elif defined(POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION) 195 return (void *)instruction_pointer; 196#else 197 return NULL; 198#endif 199} 200