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__ */