阅读 Go 源码时,我们可能经常看到只有签名(函数的第一行称为函数签名,它定义了函数的输入和输出类型)而没有实现的函数,如:
1
2
3
4
5
// src/time/sleep.go
// Sleep pauses the current goroutine for at least the duration d.
// A negative or zero duration causes Sleep to return immediately.
func Sleep(d Duration)
看上去很奇怪,没有实现?不可能的。
上面的情况,有两种可能实现:
笔者代码环境为 MacOS,go 1.19.2
函数是在汇编文件中实现的
以 LoadUint32 为例:
1
2
3
4
// src/sync/atomic/doc.go
// LoadUint32 atomically loads *addr.
func LoadUint32(addr *uint32) (val uint32)
在同目录下的 asm.s
中它是这样实现的:
1
2
3
// src/syc/atomic/asm.s
TEXT ·LoadUint32(SB),NOSPLIT,$0
JMP runtime∕internal∕atomic·Load(SB)
可以看到它的实现在 runtime∕internal∕atomic·Load(SB)
,
目录 src/runtime/internal/atomic
下有不同平台的汇编代码,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ ll /usr/local/go/src/runtime/internal/atomic/*.s
-rw-r--r-- 1 root wheel 5.1K Oct 1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_386.s
-rw-r--r-- 1 root wheel 4.0K Oct 1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_amd64.s
-rw-r--r-- 1 root wheel 5.3K Oct 1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_arm.s
-rw-r--r-- 1 root wheel 6.5K Oct 1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_arm64.s
-rw-r--r-- 1 root wheel 5.1K Oct 1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_loong64.s
-rw-r--r-- 1 root wheel 6.1K Oct 1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_mips64x.s
-rw-r--r-- 1 root wheel 4.3K Oct 1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_mipsx.s
-rw-r--r-- 1 root wheel 6.4K Oct 1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_ppc64x.s
-rw-r--r-- 1 root wheel 6.1K Oct 1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_riscv64.s
-rw-r--r-- 1 root wheel 5.9K Oct 1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_s390x.s
-rw-r--r-- 1 root wheel 269B Oct 1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_wasm.s
-rw-r--r-- 1 root wheel 3.1K Oct 1 02:17 /usr/local/go/src/runtime/internal/atomic/sys_linux_arm.s
-rw-r--r-- 1 root wheel 1.3K Oct 1 02:17 /usr/local/go/src/runtime/internal/atomic/sys_nonlinux_arm.s
我选择了 atomic_arm64.s
,里面有 .Load(SB)
的实现:
1
2
3
4
5
6
7
8
// src/runtime/internal/atomic/atomic_arm64.s
// uint32 ·Load(uint32 volatile* addr)
TEXT ·Load(SB),NOSPLIT,$0-12
MOVD ptr+0(FP), R0
LDARW (R0), R0
MOVW R0, ret+8(FP)
RET
对于有些函数,Go 选择汇编代码来实现一方面是为了考虑效率,另一方面可能是有的功能只能用汇编来实现。
通过 //go:linkname 链接实现
比如下面这个函数:
1
2
3
4
// src/time/time.go
// Provided by package runtime.
func now() (sec int64, nsec int32, mono int64)
它是由下面这个函数通过 //go:linkname time_now time.now
链接到的:
1
2
3
4
5
6
7
// src/runtime/timestub.go
//go:linkname time_now time.now
func time_now() (sec int64, nsec int32, mono int64) {
sec, nsec = walltime()
return sec, nsec, nanotime()
}