标签:pad src 汇编语言 ptr a+b poi 源文件 工具 cpu
-work
输出中间生成文件所在的目录并且在构建完成时保留中间文件。如果是比较简单的cgo代码我们也可以直接通过手工调用go tool cgo
命令来查看生成的中间文件。import "C"
指令则表示将调用cgo命令生成对应的中间文件。下图是cgo生成的中间文件的简单示意图:nocgo开头的文件中没有import "C"
指令,其它的2个文件则包含了cgo代码。cgo
命令会为每个包含了cgo代码的Go文件创建2个中间文件
,比如main.go
会分别创建main.cgo1.go 和 main.cgo2.c
两个中间文件。然后会为整个包创建一个 _cgo_gotypes.go Go
文件,其中包含Go语言部分辅助代码。此外还会创建一个_cgo_export.h 和 _cgo_export.c
文件,对应Go语言导出到C语言的类型和函数。package main
//int sum(int a, int b) { return a+b; }
import "C"
func main() {
println(C.sum(1, 1))
}
$ go tool cgo main.go
$ ls _obj | awk ‘{print $NF}‘
>>_cgo_.o
>>_cgo_export.c
>>_cgo_export.h
>>_cgo_flags
>>_cgo_gotypes.go
>>_cgo_main.c
>>main.cgo1.go
>>main.cgo2.c
_cgo_.o
、_cgo_flags
和_cgo_main.c
文件和我们的代码没有直接的逻辑关联,可以暂时忽略。main.cgo1.go
文件,它是main.go
文件展开虚拟C包相关函数和变量后的Go代码:package main
//int sum(int a, int b) { return a+b; }
import _ "unsafe"
func main() {
println(( /*line :11:13*/_Cfunc_sum /*line :11:17*/)(1, 1))
}
C.sum(1, 1)
函数调用被替换成了(_Cfunc_sum)(1, 1)
。每一个C.xxx
形式的函数都会被替换为_Cfunc_xxx
格式的纯Go函数,其中前缀_Cfunc_
表示这是一个C函数,对应一个私有的Go桥接函数。_Cfunc_sum
函数在cgo生成的_cgo_gotypes.go
文件中定义://go:cgo_unsafe_args
func _Cfunc_sum(p0 _Ctype_int, p1 _Ctype_int) (r1 _Ctype_int) {
_cgo_runtime_cgocall(_cgo_dca4a55f9b6a_Cfunc_sum, uintptr(unsafe.Pointer(&p0)))
if _Cgo_always_false {
_Cgo_use(p0)
_Cgo_use(p1)
}
return
}
_Cfunc_sum
函数的参数和返回值_Ctype_int
类型对应C.int
类型,命名的规则和_Cfunc_xxx
类似,不同的前缀用于区分函数和类型。_cgo_runtime_cgocall
对应runtime.cgocall
函数,函数的声明如下:func runtime.cgocall(fn, arg unsafe.Pointer) int32
_cgo_dca4a55f9b6a_Cfunc_sum
也是cgo生成的中间函数。函数在main.cgo2.c
定义:void
_cgo_dca4a55f9b6a_Cfunc_sum(void *v)
{
struct {
int p0;
int p1;
int r;
char __pad12[4];
} __attribute__((__packed__)) *_cgo_a = v;
char *_cgo_stktop = _cgo_topofstack();
__typeof__(_cgo_a->r) _cgo_r;
_cgo_tsan_acquire();
_cgo_r = sum(_cgo_a->p0, _cgo_a->p1);
_cgo_tsan_release();
_cgo_a = (void*)((char*)_cgo_a + (_cgo_topofstack() - _cgo_stktop));
_cgo_a->r = _cgo_r;
_cgo_msan_write(&_cgo_a->r, sizeof(_cgo_a->r));
}
struct {
int p0;
int p1;
int r;
char __pad12[4];
} __attribute__((__packed__)) *_cgo_a = v;
p0
成员对应sum的第一个参数
,p1
成员对应sum的第二个参数
,r成员,__pad12
用于填充结构体保证对齐CPU机器字的整倍数。_cgo_topofstack
函数相关的代码用于C函数调用后恢复调用栈。_cgo_tsan_acquire
和_cgo_tsan_release
则是用于扫描CGO相关的函数则是对CGO相关函数的指针做相关检查。runtime.cgocall
函数是实现Go语言到C语言函数跨界调用的关键。更详细的细节可以参考 https://golang.org/src/cmd/cgo/doc.go 内部的代码注释和 runtime.cgocall
函数的实现。package main
//int sum(int a, int b);
import "C"
//export sum
func sum(a, b C.int) C.int {
return a + b
}
func main() {} // 一定要写
// go build -buildmode=c-archive -o 生成的静态库名.a 编译的go文件.go
$ go build -buildmode=c-archive -o sum.a main.go
sum.a
静态库和sum.h
头文件。其中sum.h
头文件将包含sum函数的声明
,静态库中将包含sum函数的实现
。$ go tool cgo main.go
$ ls _obj | awk ‘{print $NF}‘
>>_cgo_.o
>>_cgo_export.c
>>_cgo_export.h
>>_cgo_flags
>>_cgo_gotypes.go
>>_cgo_main.c
>>main.cgo1.go
>>main.cgo2.c
_cgo_export.h
文件的内容和生成C静态库时产生的sum.h
头文件是同一个文件,里面同样包含sum函数的声明
。_cgo_export.c
文件中(该文件包含的是Go语言导出函数对应的C语言函数实现):int sum(int p0, int p1)
{
__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();
struct {
int p0;
int p1;
int r0;
char __pad0[4];
} __attribute__((__packed__)) a;
a.p0 = p0;
a.p1 = p1;
_cgo_tsan_release();
crosscall2(_cgoexp_3c8d95c1de14_sum, &a, 16, _cgo_ctxt);
_cgo_tsan_acquire();
_cgo_release_context(_cgo_ctxt);
return a.r0;
}
runtime/cgo.crosscall2
函数将结构体传给_cgoexp_3c8d95c1de14_sum
函数执行。func runtime/cgo.crosscall2(
fn func(a unsafe.Pointer, n int32, ctxt uintptr),
a unsafe.Pointer, n int32,
ctxt uintptr,
)
fn是中间代理函数的指针
,a是对应调用参数和返回值的结构体指针
。func _cgoexp_3c8d95c1de14_sum(a unsafe.Pointer, n int32, ctxt uintptr) {
fn := _cgoexpwrap_3c8d95c1de14_sum
_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n), ctxt);
}
func _cgoexpwrap_3c8d95c1de14_sum(p0 _Ctype_int, p1 _Ctype_int) (r0 _Ctype_int) {
return sum(p0, p1)
}
_cgoexpwrap_3c8d95c1de14_sum
作为函数指针,然后由_cgo_runtime_cgocallback
函数完成C语言到Go函数的回调工作。_cgo_runtime_cgocallback
函数对应runtime.cgocallback
函数,函数的类型如下:func runtime.cgocallback(fn, frame unsafe.Pointer, framesize, ctxt uintptr)
函数指针
,函数参数
和返回值对应结构体的指针
,函数调用帧大小
和上下文参数
。runtime.cgocallback
函数是实现C语言到Go语言函数跨界调用的关键。更详细的细节可以参考相关函数的实现。标签:pad src 汇编语言 ptr a+b poi 源文件 工具 cpu
原文地址:https://www.cnblogs.com/binHome/p/12988607.html