github.com/golang/gofrontend@v0.0.0-20240429183944-60f985a78526/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 abort(); 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 extern void main_main(void*) 203 __asm__(GOSYM_PREFIX "main.main"); 204 205 uintptr 206 getText(void) 207 { 208 return (uintptr)(const void *)(main_main); 209 } 210 211 // Return the end of the text segment, assumed to come after the 212 // read-only data section. 213 214 uintptr getEtext(void) 215 __asm__ (GOSYM_PREFIX "runtime.getEtext"); 216 217 uintptr 218 getEtext(void) 219 { 220 const void *p; 221 222 p = __data_start; 223 if (p == nil) 224 p = __etext; 225 if (p == nil) 226 p = _etext; 227 return (uintptr)(p); 228 } 229 230 // Return the start of the BSS section. 231 232 uintptr getBSS(void) 233 __asm__ (GOSYM_PREFIX "runtime.getBSS"); 234 235 uintptr 236 getBSS(void) 237 { 238 const void *p; 239 240 p = __edata; 241 if (p == NULL) 242 p = _edata; 243 if (p == NULL) 244 p = __bss_start; 245 return (uintptr)(p); 246 } 247 248 // CPU-specific initialization. 249 // Fetch CPUID info on x86. 250 251 void 252 runtime_cpuinit() 253 { 254 #if defined(__i386__) || defined(__x86_64__) 255 unsigned int eax, ebx, ecx, edx; 256 257 if (__get_cpuid(0, &eax, &ebx, &ecx, &edx)) { 258 if (eax != 0 259 && ebx == 0x756E6547 // "Genu" 260 && edx == 0x49656E69 // "ineI" 261 && ecx == 0x6C65746E) { // "ntel" 262 lfenceBeforeRdtsc = true; 263 } 264 } 265 if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) { 266 #if defined(__i386__) 267 if ((edx & bit_SSE2) != 0) { 268 hasSSE2 = true; 269 } 270 #endif 271 } 272 273 #if defined(HAVE_AS_X86_AES) 274 setSupportAES(true); 275 #endif 276 #endif 277 } 278 279 // A publication barrier: a store/store barrier. 280 281 void publicationBarrier(void) 282 __asm__ (GOSYM_PREFIX "runtime.publicationBarrier"); 283 284 void 285 publicationBarrier() 286 { 287 __atomic_thread_fence(__ATOMIC_RELEASE); 288 } 289 290 #ifdef __linux__ 291 292 /* Currently sbrk0 is only called on GNU/Linux. */ 293 294 uintptr sbrk0(void) 295 __asm__ (GOSYM_PREFIX "runtime.sbrk0"); 296 297 uintptr 298 sbrk0() 299 { 300 return syscall(SYS_brk, (uintptr)(0)); 301 } 302 303 #endif /* __linux__ */