Skip to content

Latest commit

 

History

History
85 lines (61 loc) · 4.39 KB

index.md

File metadata and controls

85 lines (61 loc) · 4.39 KB

go和其它语言互调要考虑如下几个核心问题

  • 线程与栈:
    • Go自己的函数使用的是goroutine,并使用特殊的栈(运行时可能会扩张)
    • C语言使用的是线程,并使用普通线程栈来运行,幸运的是m中的g0使用的就是这个栈。
  • 系统调用处理
    • Go运行时为了保证始终是GOMAXPROCS个P在运行,
      • 会在系统调用之前先调用runtime.entersyscall,会将P的M剥离并将它设置为PSyscall。告知系统此时其它的P有机会运行。
      • 会在系统调用之后再runtime.exitsyscall,会查看当前仍然有可用的P,则让它继续运行,否则这个goroutine就要被挂起了
    • 为了不让cgo代码影响Go的调度,Go运行时将C函数像处理系统调用一样隔离开来,要使用entersyscall、exitsyscall。
  • 垃圾回收
    • Go语言中存在GC
    • C语言中没有GC,需要依赖开发手动释放
  • 函数调用约定:调用约定规定了参数是使用寄存器,还是栈,入栈的话是从右往左,还是从左往右,堆栈是由被调用者清理,还是调用者清理
  • 内存模型

Go语言的实现中,包括如下两个关键点

  • CGO桩代码生成
    • 负责C类型和Go类型之间的转换
    • 命名空间处理以及特殊的调用方式处理
  • 运行时支持
    • 负责处理好C的运行环境,类似于给C代码一个非分段的栈空间并让它脱离与调度系统的交互
    • go调用c的核心函数是runtime.cgocall
    • c调用go的核心函数是runtime.crosscall2

调用约定

C 语言 x86架构 常用的三种调用约定:

  • cdecl,入参从右往左依次入栈,由调用者清理堆栈
  • stdcall,入参从右往左依次入栈,由被调自己清理堆栈
  • fastcall,使用 ecx、edx 传递前两个参数,剩下的参数从右向左依次入栈,且由被调自己清理堆栈

C语言x86_64架构中

  • 函数前 6 个参数通过寄存器 rdi、rsi、rdx、rcx、r8、r9 传递,超出的参数从右向左依次入栈
  • 调用方清理栈

Go1.16调用约定

  • 栈底到栈顶先储存返回参数,然后储存输入参数,
  • 压栈顺序按参数顺序从右到左。
  • main 函数分配的栈内存由 main 函数自己销毁

Go1.17之后

  • 使用 AX,BX,CX,DI,SI,R8,R9,R10,R11 传递前 9 个参数,剩余 2 个参数按从右到左的顺序依次压栈
  • 主调负责释放参数占用的栈空间

Go中使用的C编译器其实是plan9的C编译器,和gcc等会有一些区别。

内存管理

例如Golang采用垃圾回收机制,C语言采用手动释放内存机制。

内存模型

如果在 CGO 处理的跨语言函数调用时涉及到了指针的传递,则可能会出现 Go 语言和 C 语言共享某一段内存的场景

  • 在C语言中,只要没有显示释放,内存默认是一直可用的
  • 但在go语言中,可能会出现因为函数栈的动态伸缩而导致内存地址变化

在Go语言访问C中内存的时候,一般不存在问题。但在C访问Go内存的时候,可能会出现因为Go内存的动态伸缩而导致访问不安全。

对于C临时访问传入的Go内存 1、避免指针传递,全部使用值传递。不过会带来一些额外的性能开销。 2、CGO 规定在调用的 C 语言函数返回前,cgo 保证传入的 Go 语言内存在此期间不会发生移动。 但需要开发者注意:

  • 保证在取得 Go 内存后需要马上传入 C 语言函数。因为在调用CGO之前还是可能变化的
  • 在需要长时间运行的 C 语言函数需要谨慎处理参数,因为运行期间协程栈无法扩缩

如果C需要长期访问某个对象,可以以将 Go 语言内存对象在 Go 语言空间映射为一个 int 类型的 id,然后通过此 id 来间接访问和控制 Go 语言对象。 这样对象发生移动后,仍然可以通过id找到对应的值,而不会出现非法访问。

Go 语言的 new 函数分配,是由 Go 语言运行时统一管理的内存。所以默认 cgocheck 为1,检查go导出的C函数中不能返回 Go 内存。 如果需要可以将该选项调整成2或者0。

Go使用C语言的方式

  • 直接使用C语言的源代码
  • 使用C语言编译出来的静态链接库
  • 使用C语言编译出来的动态链接库

参考