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