github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/cgo/gcc_linux_arm.c (about)

     1  // Copyright 2010 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 <pthread.h>
     6  #include <string.h>
     7  #include "libcgo.h"
     8  
     9  static void *threadentry(void*);
    10  
    11  // We have to resort to TLS variable to save g(R10) and
    12  // m(R9). One reason is that external code might trigger
    13  // SIGSEGV, and our runtime.sigtramp don't even know we
    14  // are in external code, and will continue to use R10/R9,
    15  // this might as well result in another SIGSEGV.
    16  // Note: all three functions will clobber R0, and the last
    17  // two can be called from 5c ABI code.
    18  void __aeabi_read_tp(void) __attribute__((naked));
    19  void x_cgo_save_gm(void) __attribute__((naked));
    20  void x_cgo_load_gm(void) __attribute__((naked));
    21  
    22  void
    23  __aeabi_read_tp(void)
    24  {
    25  	// b __kuser_get_tls @ 0xffff0fe0
    26  	__asm__ __volatile__ (
    27  		"mvn r0, #0xf000\n\t"
    28  		"sub pc, r0, #31\n\t"
    29  		"nop\n\tnop\n\t"
    30  	);
    31  }
    32  
    33  // g (R10) at 8(TP), m (R9) at 12(TP)
    34  void
    35  x_cgo_load_gm(void)
    36  {
    37  	__asm__ __volatile__ (
    38  		"push {lr}\n\t"
    39  		"bl __aeabi_read_tp\n\t"
    40  		"ldr r10, [r0, #8]\n\t"
    41  		"ldr r9, [r0, #12]\n\t"
    42  		"pop {pc}\n\t"
    43  	);
    44  }
    45  
    46  void
    47  x_cgo_save_gm(void)
    48  {
    49  	__asm__ __volatile__ (
    50  		"push {lr}\n\t"
    51  		"bl __aeabi_read_tp\n\t"
    52  		"str r10, [r0, #8]\n\t"
    53  		"str r9, [r0, #12]\n\t"
    54  		"pop {pc}\n\t"
    55  	);
    56  }
    57  
    58  void
    59  x_cgo_init(G *g)
    60  {
    61  	pthread_attr_t attr;
    62  	size_t size;
    63  	x_cgo_save_gm(); // save g and m for the initial thread
    64  
    65  	pthread_attr_init(&attr);
    66  	pthread_attr_getstacksize(&attr, &size);
    67  	g->stackguard = (uintptr)&attr - size + 4096;
    68  	pthread_attr_destroy(&attr);
    69  }
    70  
    71  
    72  void
    73  _cgo_sys_thread_start(ThreadStart *ts)
    74  {
    75  	pthread_attr_t attr;
    76  	pthread_t p;
    77  	size_t size;
    78  	int err;
    79  
    80  	// Not sure why the memset is necessary here,
    81  	// but without it, we get a bogus stack size
    82  	// out of pthread_attr_getstacksize.  C'est la Linux.
    83  	memset(&attr, 0, sizeof attr);
    84  	pthread_attr_init(&attr);
    85  	size = 0;
    86  	pthread_attr_getstacksize(&attr, &size);
    87  	ts->g->stackguard = size;
    88  	err = pthread_create(&p, &attr, threadentry, ts);
    89  	if (err != 0) {
    90  		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
    91  		abort();
    92  	}
    93  }
    94  
    95  extern void crosscall_arm2(void (*fn)(void), void *g, void *m);
    96  static void*
    97  threadentry(void *v)
    98  {
    99  	ThreadStart ts;
   100  
   101  	ts = *(ThreadStart*)v;
   102  	free(v);
   103  
   104  	ts.g->stackbase = (uintptr)&ts;
   105  
   106  	/*
   107  	 * _cgo_sys_thread_start set stackguard to stack size;
   108  	 * change to actual guard pointer.
   109  	 */
   110  	ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096 * 2;
   111  
   112  	crosscall_arm2(ts.fn, (void *)ts.g, (void *)ts.m);
   113  	return nil;
   114  }