【底层原理:深入理解计算机系统】#1 一切从"hello world"说起 (一)
计算机系统是由硬件和系统软件组成的,他们共同工作来运行应用程序。虽然系统的具体实现方式随着时间不断的在变化,但是系统的内在概念却没有改变的。
所有的计算机硬件和软件有着相似的结构和功能。这个系列专题便是总结自己在学习底层过程中对这些组件工作原理和其对程序的影响。
通过学习,我们将会知道一些窍门来优化自己的C代码,以充分利用现代处理器和存储器系统的设计。将了解编译器是如何实现过程调用的,以及如何利用这些知识避免缓冲区溢出带来的安全漏洞。
现在我们从一个简单的入门程序hello world引入系统到底发生了什么。what's going on there?
1 #include<stdio.h>
2 int main()
3 {
4 printf("hello,world\n")
5 return 0;
6 }
以后我们把helloworld程序简称为hw。(huawei?)
hw的程序生命周期是从一个源程序(源文件)开始的,即程序员通过dev,vc6,vs之类的编辑器创建的文本文件。就是你打的很熟练的那堆代码。
文件名是hw.c(以后都以C语言为例)
源程序实际上就是一个由值0和1组成的位(bit)序列,8个位被称为一组,称为字节。每个字节表示程序中的某些文本字符。
大部分现代计算机都使用ASCII标准来表示文本字符。(American Standard Code for Information Interchange: 美国信息交换标准代码),这种方式实际上就是一个唯一的单字节大小的整数值来表示每个字符。
比如,ASCII表示的hw程序:
# i n c l u d e SP < s t d i o . h >
35 105 110 99 108 117 100 101 32 60 115 116 100 105 111 46 104 62
余下几行就不多赘述了
由此你发现规律了没。就是hw.c是以字节序列的方式储存在文件中的。每一个字节都有一个整数值。前面我们说过了8位(bit)是一个字节。也就是说这些数字可以用8个二进制数的格式保存着。
注意:这里每行代码后面都有一个隐藏的换行符 \n 来结束的,它对应的ASCII值是10。像hw.c这样只由ASCII字符构成的文件称为文本文件,其他所有文件都称为二进制文件。
hw.c的表示方法说明了一个基本的思想,系统中的所有信息(磁盘里的文件,视频,网络传输的表情)都是由一串位(bit)表示的。区分这些不同数据对象的唯一方法是我们读到这些数据对象的上下文。比如在不同的上下文中,一个同样的字节序列可能表示一个整数、浮点数、字符串或者机器指令。举例来说就好比一块猪排,放到两片面包里是汉堡,放到面皮里是手抓饼。这都取决于一个背景情况。
作为程序员,我们需要了解数字的机器表示方式,因为它们与实际的整数和实数是不同的。它们是真实值的有限近似值,这个我们之后再谈。
程序也会被其他程序翻译成其他的不同格式
hw程序的生命周期是从一个高级语言C语言程序开始的,因为这种形式能够被人读懂。然而,为了在系统上运行hw.c,每条C语句都必须被其他的程序转化为一系列低级的机器语言指令。进一个例子,假如我们现在存在所有活过的人们,意思就是,我们和王朝百姓,部落勇士,原始猿人都生活在一起。但是我们不能直接和猿人交流,我们要把说的话让王朝百姓翻译,王朝百姓给部落人翻译,最终部落人再把我们的意思解释给猿人。
C语言语句转化成机器语言后,按照一种称为可执行目标程序的格式打好包,并以前面说过的二进制磁盘文件的形式存放起来。目标程序也叫做可执行目标文件,
在Unix系统上,从源文件到目标文件的转化是由编译器驱动程序完成的:
linux> gcc -o hello hello.c
这里,GCC编译器驱动程序读取源程序文件hw.c并把它翻译成一个可执行的目标文件hw。这个过程分为四个阶段完成,如下:

我们将对每个过程进行一个分析。
预处理阶段:预处理器(cpp)根据以#开头的命令,修改原始的C程序。比如hw.c中的#incloude<stdio.h>命令,告诉预处理器读取系统头文件stdio.h的内容,并把它直接插入程序的文本中。结果得到了一个很长的C代码程序,通常以i为文件名后缀。
编译阶段:编译器(ccl)将文本文件hw.i翻译成文本文件hw.s它包含一个汇编语言程序。该程序包含函数main的定义:
1 main:
2 subq $8,%rsp
3 movl $.LCO, %edi
4 call puts
5 movl $0, %eax
6 addq $8, %rsp
7 ret
在2至7行定义中每一行语句都以一种文本格式的方式描述了一条机器指令。在后期我们会详细地学习汇编语言
汇编阶段:接下来,汇编器as将hw.s翻译成机器语言指令,把这些指令打包生成一种叫做可重定位目标程序的格式,并将结果保存在hw.o中。hw.o是一个二进制的文件,它包含的17个字节是函数main的指令编码。若用文本编辑器之类的打开它,则看到的就是一团乱码。
链接阶段:这个时候我们要注意我们在源代码中调用了printf这个函数,它是编译器提供的标准C库中的一个函数。printf函数存在于一个名为printf.o的单独预编译好的目标文件中,这个文件会合并到我们的之前的hw.o程序中,链接器ld就负责这种合并。最后得到hw(无后缀名)文件。他是一个可执行文件,可以被加载到内存中。
了解这些底层编译原理对我们有何帮助呢?
对于类似helloworld这样简单的程序,我们可以依靠编译系统生成正确有效的机器代码。但是,很多稍微复杂点的程序在编译过程中就会产生一些需要动脑的问题。
优化程序性能。为了使我们的代码更高效,我们需要去了解一些机器代码以及编译器是咋把语言代码转化成机器代码的方式的。比如一些你可能从来没想过的小问题:switch语句和if-else效率是一样的吗?谁更快,谁占用的系统资源更少?while和for循环在系统内部是执行一样的指令吗?为什么有时候简单地重新排列了一下算术表达式中的括号就可让程序运行的更快?
理解报错:编译器报错大家都见怪不怪了吧,提示的错误代码,我们都会复制到百度谷歌中去查看解决办法。但是如果我们深入地了解了编译器以及系统底层原理,对于报错就会有大大的理解和扫除一些盲区的能力。比如链接器报错说它无法解析一个引用。为啥有些程序编译不报错,当你写好了520表白程序给女友时,她一打开就是一个经典的windows报错提示信息?
避免安全漏洞:对于渗透测试学习的朋友们最能懂了吧,比如缓冲区溢出,还有很多像ms17永恒之蓝ms14之类的安全漏洞,都是在底层层面的研究问题。也许我们大可在360里面打几个漏洞补丁。但如果你深入去理解,这对你大有裨益。
我们的helloword程序目前卡在了刚变成一团乱乎乎的二进制文件这个阶段,下期将进入更深层的阶段
【底层原理:深入理解计算机系统】#1 一切从"hello world"说起 (一)的更多相关文章
- 【T-SQL进阶】02.理解SQL查询的底层原理
本系列[T-SQL]主要是针对T-SQL的总结. [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础]02.联接查询 [T-SQL基础]03.子查询 [T-SQL基础]04.表表达式 ...
- 理解SQL查询的底层原理
阅读目录 一.SQL Server组成部分 二.查询的底层原理 本系列[T-SQL]主要是针对T-SQL的总结. T-SQL基础 [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础] ...
- 理解java容器底层原理--手动实现HashMap
HashMap结构 HashMap的底层是数组+链表,百度百科找了张图: 先写个链表节点的类 package com.xzlf.collection2; public class Node { int ...
- Linux从头学06:16张结构图,彻底理解【代码重定位】的底层原理
作 者:道哥,10+年的嵌入式开发老兵. 公众号:[IOT物联网小镇],专注于:C/C++.Linux操作系统.应用程序设计.物联网.单片机和嵌入式开发等领域. 公众号回复[书籍],获取 Linux. ...
- 《深入理解计算机系统》【PDF】下载
<深入理解计算机系统>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382303 内容提要 本书主要介绍了计算机系统的基本概念,包 ...
- 《深入理解计算机系统V2》学习指导
<深入理解计算机系统V2>学习指导 目录 图书简况 学习指导 第一章 计算机系统漫游 第二章 信息的表示和处理 第三章 程序的机器级表示 第四章 处理器体系结构 第五章 优化程序性能 第六 ...
- 深入理解计算机系统(4.1)---X86的孪生兄弟,Y86指令体系结构
引言 各位猿友们好,计算机系统系列很久没更新了,实在是抱歉之极.新的一年,为了给计算机系统系列添加一些新的元素,LZ将其更改为书的原名<深入理解计算机系统>.这本书非常厚,而且难度较高,L ...
- Neo4j图数据库简介和底层原理
现实中很多数据都是用图来表达的,比如社交网络中人与人的关系.地图数据.或是基因信息等等.RDBMS并不适合表达这类数据,而且由于海量数据的存在,让其显得捉襟见肘.NoSQL数据库的兴起,很好地解决了海 ...
- CSAPP(深入理解计算机系统)读后感
9月到10月8号,包括国庆七天,大概每天5小时以上的时间,把Computer System: A Programmer Perspective 2rd version(深入理解计算机系统)的英文版啃完 ...
随机推荐
- 17.3.13---socket网络套接字介绍--函数和数据类型
1----Socket类型 套接字格式:socket(family,type[,protocal])使用给定的地址族,套接字类型,协议编号(默认为0)来创建套接字 socket类型 描述 socket ...
- Codeforces Round #517 (Div. 2)(1~n的分配)
题:https://codeforces.com/contest/1072/problem/C 思路:首先找到最大的x,使得x*(x+1)/2 <= a+b 那么一定存在一种分割使得 a1 &l ...
- spring02-组件注册-@ComponentScan-自动扫描组件&指定扫描规则
上一篇我们讲到,讲@Bean注解标在某个方法上,那么ioc容器启动的时候就会将方法返回值放到ioc容器中 在开发中,实际上包扫描用的比较多,接下来我们会介绍两种方式一种是基于xml,一种是基于注解. ...
- ubuntu linux下解决“no java virtual machine was found after searching the following locations:”的方法
现象:删除旧的jdk,安装新的jdk之后,打开eclipse报错: A Java Runtime Environment (JRE) or Java Development Kit (JDK)must ...
- 50)PHP,单例模式
class B{ ; private static $instance; private function __construct(){} public static function getNew( ...
- day21-双下eq方法
class Goods: def __init__(self,name): self.name = name def __eq__(self,other): #self = apple1, other ...
- docker里修改时间
在docker容器里,你会发现,你根本无法通过命令修改时间.这时我们就可以通过/etc/localtime这个配置文件修改时间了.但这个配置文件是一个二进制的文件,里面根本就是一堆乱码.所以我只好拷贝 ...
- jquery JavaScript如何监听button事件
下面的html页面中有两个按钮 <div class="layui-tab-item layui-show"> <form class="layui-f ...
- android采用MVP完整漫画APP、钉钉地图效果、功能完善的音乐播放器、仿QQ动态登录效果、触手app主页等源码
Android精选源码 一个可以上拉下滑的Ui效果,觉得好看可以学学 APP登陆页面适配 一款采用MVP的的完整漫画APP源码 android实现钉钉地图效果源码 一个使用单个文字生成壁纸图片的app ...
- [LC] 224. Basic Calculator
Implement a basic calculator to evaluate a simple expression string. The expression string may conta ...