《程序员看计算机系统》读书笔记之 Hello World的一生(更新中...)

书记

计算机系统由硬件和系统软件共同组成,用来执行应用程序。系统的具体执行方式可能会逐渐变化,但操作系统本身的理念是不变的。本书通过深入了解系统组件(硬件和软件)的工作机理及其对程序的影响来帮助程序员写出更快更稳定的程序。本书的目标是让人理解程序在运行时系统到底做了什么以及原因。首先会从hello world程序开始,追溯整个运行周期:从它的诞生,运行,输出,到最后结束。在这期间会简单介绍一些核心的概念,术语,以及运行程序必要的组件。这些内容在后续章节中还会展开讨论。

C语言简史

在上世纪70年代初,两个名不见经传的人搞出来了一个叫C的语言。在1989年,美国国标核准了C语言标准。这个标准将C定义为一系列功能库,也就是众所周知的C标准库。但是为啥C这么成功呢?

首先,C与Unix操作系统有过深入交易。C在最开始就是为了编写Unix系统开发的。Unix的内核,支持的工具和库基本上都使用C写的。在70、80年代,Unix在大学中风行的时候,许多人都接触到了C,然后拜倒在了C的石榴裙下。另外,因为Unix基本上是用C写的,所以可以方便的移植到其它新机器上,这让Unix和c得到了进一步发展。

其次,C简单小巧。C是由一个人主导设计出来的,而不是一群人,结果就是C小而简洁。C语言那本圣经级教科书《C编程语言》只用了261页把整个语言,标准库都讲清楚了,还顺带附赠一堆例子。正是因此,C语言相对好学,移植到不同的计算机也很方便。

最后,C是根据实际需求开发的。C是用于Unix系统开发的,后来人们发现直接用系统语言编的程序真香。C语言是系统级程序的内定语言,当然应用程序也有一大筐,但是它并不适用于所有情况;C中的指针常常会要了程序员的老命;C也缺少对于类、对象以及异常处理的小白级支持文档。而新一些的语言比如C++,JAVA都是针对应用级程序的,相关支持工作处理的更好

GNU计划

GNU计划始于1984年,目标是开发出来一个类似Unix但可以自由地修改和发行的系统,一个自由软件系统(自由软件意味着使用者有运行、复制、发布、研究、修改和改进该软件的自由)。本文使用的gcc编译系统就是GNU计划的产物之一。现在市面上GNU的内核基本都是Linux,而常说的Linux系统其实应该叫做“GNU/LINUX”系统。当然,GNU也有自己的内核,它叫做Hurd,目前仍在开发完善中。

Hello World的一生

从.c到.exe

本节展示Hello World程序是如何从编辑器中保存的.c文件一步步变为可执行文件的。

#include <stdio.h>

int main()
{
    printf("hello, world\n");
    return 0;
}

Hello酱的一生是从源代码文件开始的:在编辑器中写好代码并保存成一个叫做hello.c的文本文件。这个文件是由一堆bits(位)组成的,每个位的值是0或1,8个位是一个字节,字节表示程序中的字符。

多数计算机系统都用ASCII标准编码字符,每一个字符对应一个独一无二的ASCII码。只得注意的是,每行文本的末尾都由换行符“\n”换行,它的ASCII码是10。像hello.c这样包含“\n”这种额外字符的是文本文件,其它的则是二进制文件。

hello.c文件告诉了我们一个浅显的道理:所有系统中的信息都是由一堆“位”构成的。区别在于它们使用的语境。同样的一堆字节可以用来表示整数,也可以用来表示浮点数,字符串或者机器指令。

为了让我们自己看懂,Hello酱是由高级语言C写成的,但是如果想要执行,C语句需要被其它程序翻译成低级的机器语言指令。这些指令接下来封装成可执行对象,以二进制文件的形式存在磁盘上。这些可执行对象也叫可执行文件。在Unix系统中,负责翻译工作的就是一个叫做“编译驱动器”的东西。

linux> gcc -o hello hello.c

这行代码的意思就是gcc这个编译器读取hello.c文件编译成一个叫hello的可执行文件。代码分四步骤执行,源文件分别经过预处理器,编译器,汇编器,连接器处理后生成可执行程序。这四步放在一起叫做编译系统。

第一步,预处理。这一步会执行所有“#”开头的语句,把它们直接插入到源代码中生成一个.i结尾的文件,这个文件本质还是一个C程序,还是文本文件格式。

第二步,进行编译。编译器把.i文件翻译成汇编指令保存为.s文件,如果打开.s文件,会
在这里插入图片描述
因为它看起来是这样的

subq $8, %rsp 
movl $.LC0, %edi 
call puts 
movl $0, %eax 
addq $8, %rsp 
ret

这张图中的代码用低一级的汇编语言指令翻译了main。为什么要这么做呢?因为从这里开始各种编程语言就是一家人了。所有高级语言的编译器在这一步输出的文件都是汇编语言,天下大同了。

第三步,汇编器翻译。汇编器会把.s文件继续向下一层语言翻译,把汇编语言翻译成机器语言,然后打包成一种叫做可重定位目标文件的东西,存成.o的二进制文件。都到机器语言了,肯定是二进制文件了啊。如果用vi打开看一下,大概是这样的。
在这里插入图片描述
第四步,链接器进行连接。这个程序中调用了printf函数,一个标准库中的函数。这个函数是预编译好的存在一个叫做printf.o的文件中。如果想要我们的程序正常运行,就需要把printf.o和hello.o整合在一起,而链接器就是干这个的。在整合完之后,就会输出最后的可执行文件了。此时可执行文件仍是二进制文件。
以上就是编译系统的工作过程,但是为什么要了解编译系统呢?

  • 优化程序性能:比如是用一串“if else”组合,还是用“switch”;“while”和“for”循环哪个更有效率;将全局变量导入成局部变量后,循环为什么会更快等等。
  • 理解链接器错误
  • 避免系统漏洞,比如缓冲区溢出漏洞

执行.exe

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值