深入理解计算机系统学习笔记(一)计算机系统漫游

Posted by gaoy on April 17, 2018

第一话 —- 计算机系统漫游

计算机系统是由硬件和系统软件组成,他们共同工作来运行应用程序。话说我如果全力投身学习本书中的概念,完全理解底层计算机系统以及它对应用程序的影响,那么会成为凤毛麟角的”权威”程序员。 希望如此,我尽力理解吧。


实践技巧,比如如何避免由计算机表示数字的方式导致的奇怪的数字错误。通过小窍门优化C代码,充分理解现代处理器和存储器系统的设计将了解到编译器是如何实现过程调用的, 以及如何利用这些知识避免缓冲区溢出错误带来的安全漏洞,还可以自己试着编写自己的unix外壳自己的动态存储分配包,甚至是自己的web服务器,认识到并发带来的希望和陷阱。

#include <stdio.h>

int main()
{

	printf("hello,gaoy\n")

}

//c hello 程序

从跟踪hello程序的生命周期开始对系统的—-从它被程序员创建,到在系统上运行,输出简单的消息,然后终止。我们将沿着这个程序的生命周期,简要的介绍一些逐渐出现的关键概念,专业术语和组成部分(咋成了抄书了咧)

hello.c 程序的生命周期是从一个高级C语言程序开始的,因为这种形式能够被人读懂。然而在系统上运行hello.c程序,每条C语句都必须被其他程序转化为一系列的低级语言指令。然后这些指令按照一种称为可执行目标程序的格式打好包。并以二进制磁盘文件的形式存放起来。目标程序也称为可执行目标文件。

在Unix系统上,从源文件到目标文件的转化是由编译器驱动程序完成的:

unix > gcc -o hello hello.c

在这里gcc驱动程序读取源程序文件hello。c 并把它翻译成一个可执行目标文件hello。 这个翻译的过程可分为四个阶段完成,执行这四个阶段的程序(预处理器、编译器、汇编器和链接器)一起构成编译系统

img_c_compile

预处理阶段。

    预处理器(cpp)根据以字符#开头的命令,修改原始的C程序。
    比如hello.c中第一行的#include <stdio.h> 命令告诉预处理器读取系统头文件stdio.h的内容,
    并把它直接插入到程序文本中。结果就得到了另一个 C程序,通常是以.i 作为文件扩展名。

编译阶段。

    编译器(ccl) 将文本文件hello.i 翻译成文本文件hello.s,它包含一个汇编语言程序。汇编语言程序中的每条语句都以一种标准
    的文本格式确切地描述了一条低级机器语言指令。汇编语言非常有用,它为不同高级语言的不同编译器提供了通用的输出语言。
    例如,C编译器和Fortran编译器产生的输出文件用的都是一样的汇编语言。

汇编阶段

    接下来,汇编器(as)将hello.s翻译成机器语言指令,把这些指令打包成一种叫做 **可重定位目标程序**的格式,并将结果保存在目标文件hello.o中。
    hello.o 文件是一个二进制文件,它的字节编码是机器语言指令而不是字符。
    如果在文本编辑器中打开hello.c文件,看到的将是一堆乱码.

链接阶段

    hello 程序调用了printf函数,它是每个C编译器都会提供的标准C库中的一个函数。
    printf函数存在于一个名为printf.o的单独的预编译好了的目标文件中,
    而这个文件必须以某种方式合并到我们的hello.o程序中。
    链接器(ld) 就负责处理这种合并。结果就得到hello文件,它是一个可执行目标文件(或称为可执行文件),可以
    被加载到内存中,由系统执行。

GNU项目 穿插

GCC是GNU(GNU's Not Unix的缩写) 项目开发出来的众多有用工具之一。
GNU项目已经开发出了一个包含Unix操作系统的所有主要部件的环境,但内核除外,内核是由Linux
项目独立 发展而来的。GNU环境包括emacs编辑器、GCC编译器,GDB调试器,汇编器,链接器,处理二进制文件的工具以及其他一些部件。

***

处理器读并解释存储在存储器中的指令

此刻,hello.c 源程序已经被编译系统翻译成了可执行目标文件hello,并存放在磁盘上。要想在Unix系统上运行该可执行文件,我们将
它的文件名输入到称为外壳(shell)的应用程序中:

> ./hello
hello,gaoy

外壳是一个命令行解释器,他输入一个提示符,等待你输入一个命令,然后执行这个命令。如果该命令行的第一个单词不是一个内置外壳命令
那么外壳就会假设这是一个可执行文件的名字。hello程序在屏幕上输出到他的信息,然后终止。外壳随后输出一个提示符,等待下一个输入的指令。