我们可以调用os.Args来得到程序的参数

比如如下的调用

开始看源代码。可以看到os.Args是一个全局变量,其是调用的os.runtime_args函数来初始化的。

os.runtime_args没有函数体,其实现一定在其他的地方。而且这儿有个注释,直接说这个代码是在runtime里面实现的。

搜索一下runtime代码库,确实在里面

在runtime/runtime.go里面,注意这儿有一个特殊的指令,其会导致名字为os_runtime_args的函数在编译的时候生成的符号为os.runtime_args(使用这个指令相当于破坏了包的模块化,毕竟可以在runtime包里面写os包的东西,所以基本只有在runtime里面才会看到这种语法)。它的实现就是把argslice的值复制一份返回了。
//go:linkname os_runtime_args os.runtime_args
搜索代码库,可以看到argslice就是在runtime.goargs里面初始化的。其逻辑也很直接,在argc和argv之后,将相应的字符串逐个复制出来

那argc,argv本身又是怎么被初始化的

可以看到是在runtime.args中初始化的

runtime.args本身是在runtime.rt0_go初始化的,runtime.rt0_go调用runtime.args的时候会把系统调用那边过来的argc,argv都传过来

还有就是runtime.goargs是什么时候调用的?搜索代码库可以看到是在runtime.schedinit中调用的。而从上面可以看到runtime.schedinit是在runtime.rt0_go中调用的,而且是在runtime.args的后面

整个流程总结起来如下。
go runtime启动的时候,调用runtime.rt0_go,其中会调用runtime.args初始化argc,argv,然后会调用runtime.goargs,根据argc,argv的值来构造出runtime.argslice,这样值本身已经存在。在代码中使用os.Args的时候,就是简单的将runtime.argslice复制一份的事情了。
runtime.rt0_go runtime.args 初始argc,argv runtime.goargs 通过argc,argv构造出runtime.argslice os.Args -> os.runtime_args (使用runtime.argslice构造出来)