1 /* ====================================================================
2 * Copyright (c) 2005 The OpenSSL Project. Rights for redistribution
3 * and usage in source and binary forms are granted according to the
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
28 #if defined(__xlC__) && __xlC__>=0x600 && (defined(_POWER) || defined(_ARCH_PPC))
29 static 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());
40 # define FIPS_ref_point FIPS_text_start
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.
47 const unsigned int FIPS_rodata_start[] =
48 { 0x46495053, 0x5f726f64, 0x6174615f, 0x73746172 };
50 # define FIPS_ref_point FIPS_text_end
51 const unsigned int FIPS_rodata_end[] =
52 { 0x46495053, 0x5f726f64, 0x6174615f, 0x656e645b };
56 * I declare reference function as static in order to avoid certain
57 * pitfalls in -dynamic linker behaviour...
59 static void *instruction_pointer(void)
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
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
88 __asm __volatile("move %1,$31\n\t" /* save ra */
89 "bal .+8; nop\n\t" "move %0,$31\n\t"
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
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
108 __asm __volatile("mov %%o7,%1\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 */
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
126 mov scratch, eax} ret = (void *)((size_t)scratch & ~3UL);
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...
136 void *FIPS_ref_point()
138 #if defined(INSTRUCTION_POINTER_IMPLEMENTED)
139 return instruction_pointer();
141 * Below we essentially cover vendor compilers which do not support
142 * inline assembler...
147 } *p = (void *)instruction_pointer;
149 #elif defined(_HPUX_SOURCE)
150 # if defined(__hppa) || defined(__hppa__)
153 } *p = (void *)FIPS_ref_point;
155 if (sizeof(p) == 8) /* 64-bit */
157 else if ((size_t)p & 2) {
158 p = (void *)((size_t)p & ~3UL);
162 # elif defined(__ia64) || defined(__ia64__)
164 unsigned long long ip, gp;
165 } *p = (void *)instruction_pointer;
166 return (void *)(size_t)p->ip;
168 #elif (defined(__VMS) || defined(VMS)) && !(defined(vax) || defined(__vax__))
169 /* applies to both alpha and ia64 */
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 */
178 } *p = (void *)instruction_pointer;
180 #elif defined(_WIN32)
181 # if defined(_WIN64) && defined(_M_IA64)
184 } *p = (void *)FIPS_ref_point;
187 return (void *)FIPS_ref_point;
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]...
194 #elif defined(POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION)
195 return (void *)instruction_pointer;