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 // Cgo call and callback support. 6 // 7 // To call into the C function f from Go, the cgo-generated code calls 8 // runtime.cgocall(_cgo_Cfunc_f, frame), where _cgo_Cfunc_f is a 9 // gcc-compiled function written by cgo. 10 // 11 // runtime.cgocall (below) locks g to m, calls entersyscall 12 // so as not to block other goroutines or the garbage collector, 13 // and then calls runtime.asmcgocall(_cgo_Cfunc_f, frame). 14 // 15 // runtime.asmcgocall (in asm_$GOARCH.s) switches to the m->g0 stack 16 // (assumed to be an operating system-allocated stack, so safe to run 17 // gcc-compiled code on) and calls _cgo_Cfunc_f(frame). 18 // 19 // _cgo_Cfunc_f invokes the actual C function f with arguments 20 // taken from the frame structure, records the results in the frame, 21 // and returns to runtime.asmcgocall. 22 // 23 // After it regains control, runtime.asmcgocall switches back to the 24 // original g (m->curg)'s stack and returns to runtime.cgocall. 25 // 26 // After it regains control, runtime.cgocall calls exitsyscall, which blocks 27 // until this m can run Go code without violating the $GOMAXPROCS limit, 28 // and then unlocks g from m. 29 // 30 // The above description skipped over the possibility of the gcc-compiled 31 // function f calling back into Go. If that happens, we continue down 32 // the rabbit hole during the execution of f. 33 // 34 // To make it possible for gcc-compiled C code to call a Go function p.GoF, 35 // cgo writes a gcc-compiled function named GoF (not p.GoF, since gcc doesn't 36 // know about packages). The gcc-compiled C function f calls GoF. 37 // 38 // GoF calls crosscall2(_cgoexp_GoF, frame, framesize). Crosscall2 39 // (in cgo/gcc_$GOARCH.S, a gcc-compiled assembly file) is a two-argument 40 // adapter from the gcc function call ABI to the 6c function call ABI. 41 // It is called from gcc to call 6c functions. In this case it calls 42 // _cgoexp_GoF(frame, framesize), still running on m->g0's stack 43 // and outside the $GOMAXPROCS limit. Thus, this code cannot yet 44 // call arbitrary Go code directly and must be careful not to allocate 45 // memory or use up m->g0's stack. 46 // 47 // _cgoexp_GoF calls runtime.cgocallback(p.GoF, frame, framesize). 48 // (The reason for having _cgoexp_GoF instead of writing a crosscall3 49 // to make this call directly is that _cgoexp_GoF, because it is compiled 50 // with 6c instead of gcc, can refer to dotted names like 51 // runtime.cgocallback and p.GoF.) 52 // 53 // runtime.cgocallback (in asm_$GOARCH.s) switches from m->g0's 54 // stack to the original g (m->curg)'s stack, on which it calls 55 // runtime.cgocallbackg(p.GoF, frame, framesize). 56 // As part of the stack switch, runtime.cgocallback saves the current 57 // SP as m->g0->sched.sp, so that any use of m->g0's stack during the 58 // execution of the callback will be done below the existing stack frames. 59 // Before overwriting m->g0->sched.sp, it pushes the old value on the 60 // m->g0 stack, so that it can be restored later. 61 // 62 // runtime.cgocallbackg (below) is now running on a real goroutine 63 // stack (not an m->g0 stack). First it calls runtime.exitsyscall, which will 64 // block until the $GOMAXPROCS limit allows running this goroutine. 65 // Once exitsyscall has returned, it is safe to do things like call the memory 66 // allocator or invoke the Go callback function p.GoF. runtime.cgocallbackg 67 // first defers a function to unwind m->g0.sched.sp, so that if p.GoF 68 // panics, m->g0.sched.sp will be restored to its old value: the m->g0 stack 69 // and the m->curg stack will be unwound in lock step. 70 // Then it calls p.GoF. Finally it pops but does not execute the deferred 71 // function, calls runtime.entersyscall, and returns to runtime.cgocallback. 72 // 73 // After it regains control, runtime.cgocallback switches back to 74 // m->g0's stack (the pointer is still in m->g0.sched.sp), restores the old 75 // m->g0.sched.sp value from the stack, and returns to _cgoexp_GoF. 76 // 77 // _cgoexp_GoF immediately returns to crosscall2, which restores the 78 // callee-save registers for gcc and returns to GoF, which returns to f. 79 80 package runtime 81 82 import "unsafe" 83 84 // Call from Go to C. 85 //go:nosplit 86 func cgocall(fn, arg unsafe.Pointer) int32 { 87 if !iscgo && GOOS != "solaris" && GOOS != "windows" { 88 throw("cgocall unavailable") 89 } 90 91 if fn == nil { 92 throw("cgocall nil") 93 } 94 95 if raceenabled { 96 racereleasemerge(unsafe.Pointer(&racecgosync)) 97 } 98 99 /* 100 * Lock g to m to ensure we stay on the same stack if we do a 101 * cgo callback. Add entry to defer stack in case of panic. 102 */ 103 lockOSThread() 104 mp := getg().m 105 mp.ncgocall++ 106 mp.ncgo++ 107 defer endcgo(mp) 108 109 /* 110 * Announce we are entering a system call 111 * so that the scheduler knows to create another 112 * M to run goroutines while we are in the 113 * foreign code. 114 * 115 * The call to asmcgocall is guaranteed not to 116 * split the stack and does not allocate memory, 117 * so it is safe to call while "in a system call", outside 118 * the $GOMAXPROCS accounting. 119 */ 120 entersyscall(0) 121 errno := asmcgocall(fn, arg) 122 exitsyscall(0) 123 124 return errno 125 } 126 127 //go:nosplit 128 func endcgo(mp *m) { 129 mp.ncgo-- 130 131 if raceenabled { 132 raceacquire(unsafe.Pointer(&racecgosync)) 133 } 134 135 unlockOSThread() // invalidates mp 136 } 137 138 // Helper functions for cgo code. 139 140 func cmalloc(n uintptr) unsafe.Pointer { 141 var args struct { 142 n uint64 143 ret unsafe.Pointer 144 } 145 args.n = uint64(n) 146 cgocall(_cgo_malloc, unsafe.Pointer(&args)) 147 if args.ret == nil { 148 throw("C malloc failed") 149 } 150 return args.ret 151 } 152 153 func cfree(p unsafe.Pointer) { 154 cgocall(_cgo_free, p) 155 } 156 157 // Call from C back to Go. 158 //go:nosplit 159 func cgocallbackg() { 160 gp := getg() 161 if gp != gp.m.curg { 162 println("runtime: bad g in cgocallback") 163 exit(2) 164 } 165 166 // Save current syscall parameters, so m.syscall can be 167 // used again if callback decide to make syscall. 168 syscall := gp.m.syscall 169 170 // entersyscall saves the caller's SP to allow the GC to trace the Go 171 // stack. However, since we're returning to an earlier stack frame and 172 // need to pair with the entersyscall() call made by cgocall, we must 173 // save syscall* and let reentersyscall restore them. 174 savedsp := unsafe.Pointer(gp.syscallsp) 175 savedpc := gp.syscallpc 176 exitsyscall(0) // coming out of cgo call 177 cgocallbackg1() 178 // going back to cgo call 179 reentersyscall(savedpc, uintptr(savedsp)) 180 181 gp.m.syscall = syscall 182 } 183 184 func cgocallbackg1() { 185 gp := getg() 186 if gp.m.needextram { 187 gp.m.needextram = false 188 systemstack(newextram) 189 } 190 191 if gp.m.ncgo == 0 { 192 // The C call to Go came from a thread not currently running 193 // any Go. In the case of -buildmode=c-archive or c-shared, 194 // this call may be coming in before package initialization 195 // is complete. Wait until it is. 196 <-main_init_done 197 } 198 199 // Add entry to defer stack in case of panic. 200 restore := true 201 defer unwindm(&restore) 202 203 if raceenabled { 204 raceacquire(unsafe.Pointer(&racecgosync)) 205 } 206 207 type args struct { 208 fn *funcval 209 arg unsafe.Pointer 210 argsize uintptr 211 } 212 var cb *args 213 214 // Location of callback arguments depends on stack frame layout 215 // and size of stack frame of cgocallback_gofunc. 216 sp := gp.m.g0.sched.sp 217 switch GOARCH { 218 default: 219 throw("cgocallbackg is unimplemented on arch") 220 case "arm": 221 // On arm, stack frame is two words and there's a saved LR between 222 // SP and the stack frame and between the stack frame and the arguments. 223 cb = (*args)(unsafe.Pointer(sp + 4*ptrSize)) 224 case "arm64": 225 // On arm64, stack frame is four words and there's a saved LR between 226 // SP and the stack frame and between the stack frame and the arguments. 227 cb = (*args)(unsafe.Pointer(sp + 5*ptrSize)) 228 case "amd64": 229 // On amd64, stack frame is one word, plus caller PC. 230 if framepointer_enabled { 231 // In this case, there's also saved BP. 232 cb = (*args)(unsafe.Pointer(sp + 3*ptrSize)) 233 break 234 } 235 cb = (*args)(unsafe.Pointer(sp + 2*ptrSize)) 236 case "386": 237 // On 386, stack frame is three words, plus caller PC. 238 cb = (*args)(unsafe.Pointer(sp + 4*ptrSize)) 239 case "ppc64", "ppc64le": 240 // On ppc64, stack frame is two words and there's a 241 // saved LR between SP and the stack frame and between 242 // the stack frame and the arguments. 243 cb = (*args)(unsafe.Pointer(sp + 4*ptrSize)) 244 } 245 246 // Invoke callback. 247 // NOTE(rsc): passing nil for argtype means that the copying of the 248 // results back into cb.arg happens without any corresponding write barriers. 249 // For cgo, cb.arg points into a C stack frame and therefore doesn't 250 // hold any pointers that the GC can find anyway - the write barrier 251 // would be a no-op. 252 reflectcall(nil, unsafe.Pointer(cb.fn), unsafe.Pointer(cb.arg), uint32(cb.argsize), 0) 253 254 if raceenabled { 255 racereleasemerge(unsafe.Pointer(&racecgosync)) 256 } 257 258 // Do not unwind m->g0->sched.sp. 259 // Our caller, cgocallback, will do that. 260 restore = false 261 } 262 263 func unwindm(restore *bool) { 264 if !*restore { 265 return 266 } 267 // Restore sp saved by cgocallback during 268 // unwind of g's stack (see comment at top of file). 269 mp := acquirem() 270 sched := &mp.g0.sched 271 switch GOARCH { 272 default: 273 throw("unwindm not implemented") 274 case "386", "amd64": 275 sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp)) 276 case "arm": 277 sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 4)) 278 case "arm64": 279 sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 16)) 280 case "ppc64", "ppc64le": 281 sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 8)) 282 } 283 releasem(mp) 284 } 285 286 // called from assembly 287 func badcgocallback() { 288 throw("misaligned stack in cgocallback") 289 } 290 291 // called from (incomplete) assembly 292 func cgounimpl() { 293 throw("cgo not implemented") 294 } 295 296 var racecgosync uint64 // represents possible synchronization in C code 297