Go如何进行系统调用?

Go如何进行系统调用?,go,Go,据我所知,在CPython中,open()和read()——读取文件的API是用C代码编写的。C代码可能会调用一些知道如何进行系统调用的C库 像围棋这样的语言怎么样?围棋本身现在不是用围棋写的吗?是否在后台调用C库?该包负责对底层操作系统的系统调用。根据您使用的操作系统,将使用不同的软件包生成相应的调用。这里有一个指向在Unix系统上运行的Go自述文件的链接:上的部分是手写的Go文件,这些文件实现了需要特殊处理的系统调用,并且应该引导您了解其工作原理 Yes go现在用go编写。但是,进行系统调

据我所知,在CPython中,
open()
read()
——读取文件的API是用C代码编写的。C代码可能会调用一些知道如何进行系统调用的C库


像围棋这样的语言怎么样?围棋本身现在不是用围棋写的吗?是否在后台调用C库?

该包负责对底层操作系统的系统调用。根据您使用的操作系统,将使用不同的软件包生成相应的调用。这里有一个指向在Unix系统上运行的Go自述文件的链接:上的部分是手写的Go文件,这些文件实现了需要特殊处理的系统调用,并且应该引导您了解其工作原理

Yes go现在用go编写。但是,进行系统调用不需要C

需要调用的一件重要事情是,系统调用不是“用C编写的”。您可以在Unix上从C进行系统调用,因为。特别是,Linux如何定义这个头有点复杂,但您可以从总体思路中看出。系统调用是用名称和数字定义的。例如,当您调用
read
时,幕后真正发生的事情是在适当的寄存器/内存()中设置参数,然后是触发中断
0x80
的指令
syscall
。操作系统已经设置了适当的中断处理程序来接收该中断,并且操作系统开始执行该系统调用所需的任何操作。因此,进行系统调用不需要用C语言编写的东西(或标准库)。您只需要了解呼叫ABI和中断号码

然而,@retgits指出,golang的方法是利用libc已经拥有处理系统调用的所有逻辑这一事实。是一个CLI脚本,用于解析这些libc文件以提取必要的信息

如果编译go脚本,您实际上可以跟踪系统调用的生命周期,如:

主程序包
进口(
“系统调用”
)
func main(){
var buf[]字节
syscall.Read(9,buf)
}
在生成的二进制文件上运行
objdump-D
。go运行时相当大,因此最好的方法是找到
main
函数,查看它调用
syscall.Read
的位置,然后从那里搜索偏移量:
syscall.Read
calls
syscall.syscall
syscall.syscall
调用
runtime.libcCall
(它从go ABI切换到C ABI兼容性,以便参数位于操作系统期望的位置——例如,您可以看到这一点),
runtime.libcCall
调用
runtime.asmcgocall
,等等

为了获得额外的乐趣,请使用gdb运行该二进制文件,并继续执行,直到点击系统调用。

Go编译器(将Go代码转换为目标CPU代码)是用Go编写的,但这与您所说的运行时支持代码不同。标准库主要是用Go编写的,可能知道如何在不涉及C代码的情况下直接进行系统调用。但是,可能会有一些C支持代码,具体取决于目标平台。

简短的回答是“这取决于”

Go为H/W和OS的多种组合进行编译,在使用它们时,它们都有不同的方法来进行系统调用

例如,Solaris不提供稳定的受支持的系统调用集,因此它们通过系统libc进行调用-正如供应商所要求的那样

Windows确实支持一组相当稳定的系统调用,但它被定义为一组标准DLL提供的C API。 这些DLL公开的函数大多是使用单个“按编号进行系统调用”函数的函数,但这些编号没有文档记录,并且在内核风格和版本之间存在差异(可能是有意的)

Linux确实提供了一组稳定且有文档记录的编号系统调用,因此直接调用内核

现在请记住,对于Go to,“直接调用内核”意味着遵循所谓的H/W和OS组合。例如,在amd64上的现代Linux上,进行系统调用需要使用某些值填充一组CPU寄存器,进行一些其他安排,然后发出
syscenter
CPU指令

在Windows上,您必须使用其本机调用约定(即stdcall,而不是cdecl)