github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/runtime/runtime_c.c (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 #include <errno.h> 6 #include <signal.h> 7 #include <unistd.h> 8 9 #if defined(__i386__) || defined(__x86_64__) 10 #include <cpuid.h> 11 #endif 12 13 #ifdef __linux__ 14 #include <syscall.h> 15 #endif 16 17 #include "config.h" 18 19 #include "runtime.h" 20 #include "arch.h" 21 #include "array.h" 22 23 int32 24 runtime_atoi(const byte *p, intgo len) 25 { 26 int32 n; 27 28 n = 0; 29 while(len > 0 && '0' <= *p && *p <= '9') { 30 n = n*10 + *p++ - '0'; 31 len--; 32 } 33 return n; 34 } 35 36 // A random number from the GNU/Linux auxv array. 37 static uint32 randomNumber; 38 39 // Set the random number from Go code. 40 41 void 42 setRandomNumber(uint32 r) 43 { 44 randomNumber = r; 45 } 46 47 #if defined(__i386__) || defined(__x86_64__) || defined (__s390__) || defined (__s390x__) 48 49 // When cputicks is just asm instructions, skip the split stack 50 // prologue for speed. 51 52 int64 runtime_cputicks(void) __attribute__((no_split_stack)); 53 54 #endif 55 56 // Whether the processor supports SSE2. 57 #if defined (__i386__) 58 static _Bool hasSSE2; 59 60 // Force appropriate CPU level so that we can call the lfence/mfence 61 // builtins. 62 63 #pragma GCC push_options 64 #pragma GCC target("sse2") 65 66 #elif defined(__x86_64__) 67 #define hasSSE2 true 68 #endif 69 70 #if defined(__i386__) || defined(__x86_64__) 71 // Whether to use lfence, as opposed to mfence. 72 // Set based on cpuid. 73 static _Bool lfenceBeforeRdtsc; 74 #endif // defined(__i386__) || defined(__x86_64__) 75 76 int64 77 runtime_cputicks(void) 78 { 79 #if defined(__i386__) || defined(__x86_64__) 80 if (hasSSE2) { 81 if (lfenceBeforeRdtsc) { 82 __builtin_ia32_lfence(); 83 } else { 84 __builtin_ia32_mfence(); 85 } 86 } 87 return __builtin_ia32_rdtsc(); 88 #elif defined (__s390__) || defined (__s390x__) 89 uint64 clock = 0; 90 /* stckf may not write the return variable in case of a clock error, so make 91 it read-write to prevent that the initialisation is optimised out. 92 Note: Targets below z9-109 will crash when executing store clock fast, i.e. 93 we don't support Go for machines older than that. */ 94 asm volatile(".insn s,0xb27c0000,%0" /* stckf */ : "+Q" (clock) : : "cc" ); 95 return (int64)clock; 96 #else 97 // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand(). 98 // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. 99 // randomNumber provides better seeding of fastrand. 100 return runtime_nanotime1() + randomNumber; 101 #endif 102 } 103 104 #if defined(__i386__) 105 #pragma GCC pop_options 106 #endif 107 108 void 109 runtime_signalstack(byte *p, uintptr n) 110 { 111 stack_t st; 112 113 st.ss_sp = p; 114 st.ss_size = n; 115 st.ss_flags = 0; 116 if(p == nil) 117 st.ss_flags = SS_DISABLE; 118 if(sigaltstack(&st, nil) < 0) 119 *(int *)0xf1 = 0xf1; 120 } 121 122 int32 go_open(char *, int32, int32) 123 __asm__ (GOSYM_PREFIX "runtime.open"); 124 125 int32 126 go_open(char *name, int32 mode, int32 perm) 127 { 128 return runtime_open(name, mode, perm); 129 } 130 131 int32 go_read(int32, void *, int32) 132 __asm__ (GOSYM_PREFIX "runtime.read"); 133 134 int32 135 go_read(int32 fd, void *p, int32 n) 136 { 137 ssize_t r = runtime_read(fd, p, n); 138 if (r < 0) 139 r = - errno; 140 return (int32)r; 141 } 142 143 int32 go_write1(uintptr, void *, int32) 144 __asm__ (GOSYM_PREFIX "runtime.write1"); 145 146 int32 147 go_write1(uintptr fd, void *p, int32 n) 148 { 149 ssize_t r = runtime_write(fd, p, n); 150 if (r < 0) 151 r = - errno; 152 return (int32)r; 153 } 154 155 int32 go_closefd(int32) 156 __asm__ (GOSYM_PREFIX "runtime.closefd"); 157 158 int32 159 go_closefd(int32 fd) 160 { 161 return runtime_close(fd); 162 } 163 164 intgo go_errno(void) 165 __asm__ (GOSYM_PREFIX "runtime.errno"); 166 167 intgo 168 go_errno() 169 { 170 return (intgo)errno; 171 } 172 173 uintptr getEnd(void) 174 __asm__ (GOSYM_PREFIX "runtime.getEnd"); 175 176 uintptr 177 getEnd() 178 { 179 #ifdef _AIX 180 // mmap adresses range start at 0x30000000 on AIX for 32 bits processes 181 uintptr end = 0x30000000U; 182 #else 183 uintptr end = 0; 184 uintptr *pend; 185 186 pend = &__go_end; 187 if (pend != nil) { 188 end = *pend; 189 } 190 #endif 191 192 return end; 193 } 194 195 // Return an address that is before the read-only data section. 196 // Unfortunately there is no standard symbol for this so we use a text 197 // address. 198 199 uintptr getText(void) 200 __asm__ (GOSYM_PREFIX "runtime.getText"); 201 202 uintptr 203 getText(void) 204 { 205 return (uintptr)(const void *)(getText); 206 } 207 208 // Return the end of the text segment, assumed to come after the 209 // read-only data section. 210 211 uintptr getEtext(void) 212 __asm__ (GOSYM_PREFIX "runtime.getEtext"); 213 214 uintptr 215 getEtext(void) 216 { 217 const void *p; 218 219 p = __data_start; 220 if (p == nil) 221 p = __etext; 222 if (p == nil) 223 p = _etext; 224 return (uintptr)(p); 225 } 226 227 // CPU-specific initialization. 228 // Fetch CPUID info on x86. 229 230 void 231 runtime_cpuinit() 232 { 233 #if defined(__i386__) || defined(__x86_64__) 234 unsigned int eax, ebx, ecx, edx; 235 236 if (__get_cpuid(0, &eax, &ebx, &ecx, &edx)) { 237 if (eax != 0 238 && ebx == 0x756E6547 // "Genu" 239 && edx == 0x49656E69 // "ineI" 240 && ecx == 0x6C65746E) { // "ntel" 241 lfenceBeforeRdtsc = true; 242 } 243 } 244 if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) { 245 #if defined(__i386__) 246 if ((edx & bit_SSE2) != 0) { 247 hasSSE2 = true; 248 } 249 #endif 250 } 251 252 #if defined(HAVE_AS_X86_AES) 253 setSupportAES(true); 254 #endif 255 #endif 256 } 257 258 // A publication barrier: a store/store barrier. 259 260 void publicationBarrier(void) 261 __asm__ (GOSYM_PREFIX "runtime.publicationBarrier"); 262 263 void 264 publicationBarrier() 265 { 266 __atomic_thread_fence(__ATOMIC_RELEASE); 267 } 268 269 #ifdef __linux__ 270 271 /* Currently sbrk0 is only called on GNU/Linux. */ 272 273 uintptr sbrk0(void) 274 __asm__ (GOSYM_PREFIX "runtime.sbrk0"); 275 276 uintptr 277 sbrk0() 278 { 279 return syscall(SYS_brk, (uintptr)(0)); 280 } 281 282 #endif /* __linux__ */