Go和Linux:了解通话

嗨,我叫Markus Sample,最近我开始了成为一名程序员的旅程。 在我的上一篇文章(请参阅此处)中,我在Macbook上的Linux虚拟机上编写并在没有CPU仿真的情况下运行了hello world。 现在,我想了解为什么我的Linux虚拟机必须与MacOS进行不同的编译。 事实证明,这是由于系统调用引起的,但是为了理解它们,我需要对操作系统的工作原理有基本的了解。 基本上,程序会请求信息或CPU来计算信息。 这些调用中最简单的类型是函数调用。

程序可以进行函数调用,这些调用使用CPU来计算所需的任务,但不需要CPU具有特殊的安全权限。 为了完成并返回这些调用,计算机将使用堆栈和堆。 当一个函数需要某些东西时,它将一个堆栈框架放到堆栈上。 堆栈是一堆堆栈框架,由局部变量,参数和返回地址组成。 进行函数调用时,它将堆栈框架放入堆栈中(被调用的函数可能会将局部变量放入框架中)。

堆栈指针CPU寄存器将使用后进先出方法指向要放在堆栈中的最后一个堆栈帧,这意味着放在堆栈上的最后一个内容将是要指向的第一个内容。 程序计数器CPU寄存器指向需要为CPU执行的下一条指令。 当程序计数器到达函数的返回语句时,可以从堆栈中删除局部变量,从堆栈中删除返回地址并放入程序计数器中,然后从调用函数的位置继续执行。 这段视频很好地解释了堆栈。

堆是不同的。 我将其描述为一个黑板,程序可以从它们确定的空间中获取内存或在其上“绘制”。 回到函数调用,有一种特殊类型的调用,其中CPU需要特殊的安全权限才能完成请求的任务。

这些特殊调用称为系统调用,包括简单但功能强大的功能,例如读取或写入文件。 他们调用内核(它是操作系统的核心)来请求数据或执行操作。 但是它们有一个缺点,使任何旧程序都可以完全访问类似于硬件的磁盘驱动器,并且计算机上的所有RAM内存都是危险的,并且可能使它能够操纵或控制计算机以及其他用户的程序和进程。

为了避免这种情况,内核位于上锁的门后,只有系统调用才能请求密钥。 执行此操作时,运行程序的用户ID指示执行系统调用时授予的权限。 当需要执行某些操作时,您的CPU就会被放进这些锁着的门内(CPU进入特权模式),并且控制权会转移到内核,以确定它是否应提供所请求的数据或执行所请求的操作。 如果被授予,它将对其进行计算并随后将其返回。 这使请求数据的程序无法对此过程进行直接控制,从而消除了前面提到的安全风险。 由于必须先将CPU放入特权模式然后再将其退出特权模式,因此需要花费一些时间才能完成此过程,这使得需要进行大量系统调用的程序比进行较少系统调用的程序慢。 我想知道我的hello world程序在虚拟机上进行了多少次调用。

在我的Hello World程序上使用strace

事实证明,它进行了149次通话,耗时0.001016秒,还不错。 进行的主要调用是write,用于写入文本“ hello world”。 为了找到此信息,我使用了strace,它是一个可以跟踪您的程序并查看各种数据(包括系统调用)的程序。 我从strace得到的基本概念是,它将自身束缚在有问题的程序中并跟踪它的去向,并在程序完成后返回此数据。 帮助我理解strace复杂性的一个很好的例子是使用ptrace构建调试器的视频。

Ptrace是linux系统调用,具有大量的功能以及可以传递的大量参数。 当我阅读该手册时,我似乎需要更多时间才能完全理解和理解它。

现在,了解了所有这些信息,似乎没有一个如此简单的问题会得到如此复杂的答案。 在某种程度上,它没有这么复杂的答案。 您只需要所有背景信息就能理解答案。 不同的操作系统具有不同的系统调用,这就需要对Go程序进行交叉编译或重新编译,以使其可以在不同的系统上运行,同时仍执行相同的任务。

一些热衷的人可能会说,出于可执行文件格式的原因,需要交叉编译/重新编译。 Go可以编译成一个静态链接的程序,该程序已经包含该程序的所有指令,并且仅需要按摩成操作系统可以理解的文件格式或形状。 但是,必须重新编译才能处理不同的系统调用。 例如,要在MacOS上运行hello world程序,文件格式必须为Mach-O,但在交叉编译后可以在我的linux虚拟机上运行,​​文件格式为ELF。 尽管需要进行这种格式更改,但它与系统调用无关紧要,系统调用因操作系统而异,并且要求编译器生成不同的代码。 举例来说,假设我有一个立方体形状的橙色,并且要使机器将其识别为橙色,它必须是球形的。 我所要做的只是将其塑造成一个球形。 现在想象一下,当我将这种立方橙子带到一个新的操作系统中时,它希望它是金字塔形的,并且还要求橙子的内部尝起来像菠萝。 我需要将橙子塑造成金字塔形并修改内部,使其看起来像应该的样子。 使其具有应有的味道所面临的挑战是重新编译的主要原因。

但是,有两种类型的编程语言不需要编译或重新编译。 一种是解释性语言,包括Javascript,Python和PHP。 另一种是针对特定语言的虚拟机(例如Java)编译为可移植字节码的语言。 这是因为解释器和虚拟机是为那些操作系统编译的,并使其程序对其进行系统调用

学习所有这些知识以理解一个简单问题的答案对我来说真的很有趣,并且让我对一切的工作原理有了一个很好的总体认识。 但是,我想回到提高我的编码技能上,并发现我可以用它们做什么。 所有这些以及更多内容将在下次讨论和记录。 希望您能继续关注。