[go]go如何把代码运行起来的?

代码在硬盘上是一堆二进制

  • 弄清楚文件在硬盘/内存中的存储值
package main

import "fmt"

func main() {
    fmt.Println("hello world")
}

vim查看 :%!xxd

在终端里执行 man ascii

观察发现, 中间列和最右列 是一一对应的。
也就是说,刚刚写完的 hello.go 文件都是由 ASCII 字符表示的(文本文件)

  • 汇编转换位机器指令

  • go语句转换为机器指令过程

Go 程序并不能直接运行,每条 Go 语句必须转化为一系列的低级机器语言指令,将这些指令打包到一起,
并以二进制磁盘文件的形式存储起来,也就是可执行目标文件。

一般而言,先执行一些初始化的工作;
找到 main 函数的入口,执行用户写的代码;
main 函数退出;
执行一些收尾的工作,整个过程完毕。

探索编译和运行的过程。

通常将编译和链接合并到一起的过程称为构建(Build)。

编译过程就是对源文件进行词法分析、语法分析、语义分析、优化,最后生成汇编代码文件,以 .s 作为文件后缀的汇编指令。
汇编器会将汇编代码转变成机器可以执行的指令。
由于每一条汇编语句几乎都与一条机器指令相对应,所以只是一个简单的一一对应,比较简单,没有语法、语义分析,也没有优化这些步骤。
  • 编译器的作用: 将高级语言翻译成机器语言

6个阶段

  • 词法分析
#include <stdio.h>
int main(int argc, char* argv[]){
    int age = 45;
    if (age >= 17+8+20) {
        printf("Hello old man!\\n");
    }
    else{
        printf("Hello young man!\\n");
    }
    return 0;
}

我们会识别出if、else、int这样的关键字,main、printf、age这样的标识符,+、-、=这样的操作符号,还有花括号、圆括号、分号这样的符号,以及数字字面量、字符串字面量等。这些都是Token。

识别age这样的标识符。它以字母开头,后面可以是字母或数字,直到遇到第一个既不是字母又不是数字的字符时结束。

识别>=这样的操作符。 当扫描到一个>字符的时候,就要注意,它可能是一个GT(Greater Than,大于)操作符。但由于GE(Greater Equal,大于等于)也是以>开头的,所以再往下再看一位,如果是=,那么这个Token就是GE,否则就是GT。

识别45这样的数字字面量。当扫描到一个数字字符的时候,就开始把它看做数字,直到遇到非数字的字符。

  • 语法分析
    例如“2+3*5”,你会得到一棵类似下图的AST。

  • 语义分析

以“You can never drink too much water.” 这句话为例。它的确切含义是什么?
是“你不能喝太多水”,
还是“你喝多少水都不嫌多”?

实际上,这两种解释都是可以的,我们只有联系上下文才能知道它的准确含义。

词法分析是把程序分割成一个个Token的过程,可以通过构造有限自动机来实现。

语法分析是把程序的结构识别出来,并形成一棵便于由计算机处理的抽象语法树。可以用递归下降的算法来实现。

语义分析是消除语义模糊,生成一些属性信息,让计算机能够依据这些信息生成目标代码。

从上图: 将编写的一个c程序(源代码 )转换成可以在硬件上运行的程序(可执行代码 ),需要进行
    编译阶段
        先通过“编译器 “把一个 .c/.cpp 源代码 编译成 .s的汇编代码;
        再经过“汇编器 ” 把这 个.s的汇编代码汇编成 .o 的 目标代码
    链接阶段
        通过连接其他 .o 代码(如果需要的话) 库文件 和 1 中的.o 目标代码生成可执行文件

该文件流被这三种程序(红色)的加工,分别表现出四种形式(蓝色),这就是c程序的编译和链接过程。

如果再详细的话,编译器在将源文件编译成汇编文件的过程又分为:预处理阶段(生成 .i 代码) 和  优化阶段

猜你喜欢

转载自www.cnblogs.com/iiiiiher/p/12179867.html