计算机系统是由硬件和系统软件组成的,他们共同工作来运行应用程序。虽然系统的具体实现方式随着时间不断的在变化,但是系统的内在概念却没有改变的。

所有的计算机硬件和软件有着相似的结构和功能。这个系列专题便是总结自己在学习底层过程中对这些组件工作原理和其对程序的影响。

通过学习,我们将会知道一些窍门来优化自己的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"说起 (一)的更多相关文章

  1. 【T-SQL进阶】02.理解SQL查询的底层原理

    本系列[T-SQL]主要是针对T-SQL的总结. [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础]02.联接查询 [T-SQL基础]03.子查询 [T-SQL基础]04.表表达式 ...

  2. 理解SQL查询的底层原理

    阅读目录 一.SQL Server组成部分 二.查询的底层原理 本系列[T-SQL]主要是针对T-SQL的总结. T-SQL基础 [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础] ...

  3. 理解java容器底层原理--手动实现HashMap

    HashMap结构 HashMap的底层是数组+链表,百度百科找了张图: 先写个链表节点的类 package com.xzlf.collection2; public class Node { int ...

  4. Linux从头学06:16张结构图,彻底理解【代码重定位】的底层原理

    作 者:道哥,10+年的嵌入式开发老兵. 公众号:[IOT物联网小镇],专注于:C/C++.Linux操作系统.应用程序设计.物联网.单片机和嵌入式开发等领域. 公众号回复[书籍],获取 Linux. ...

  5. 《深入理解计算机系统》【PDF】下载

    <深入理解计算机系统>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382303 内容提要 本书主要介绍了计算机系统的基本概念,包 ...

  6. 《深入理解计算机系统V2》学习指导

    <深入理解计算机系统V2>学习指导 目录 图书简况 学习指导 第一章 计算机系统漫游 第二章 信息的表示和处理 第三章 程序的机器级表示 第四章 处理器体系结构 第五章 优化程序性能 第六 ...

  7. 深入理解计算机系统(4.1)---X86的孪生兄弟,Y86指令体系结构

    引言 各位猿友们好,计算机系统系列很久没更新了,实在是抱歉之极.新的一年,为了给计算机系统系列添加一些新的元素,LZ将其更改为书的原名<深入理解计算机系统>.这本书非常厚,而且难度较高,L ...

  8. Neo4j图数据库简介和底层原理

    现实中很多数据都是用图来表达的,比如社交网络中人与人的关系.地图数据.或是基因信息等等.RDBMS并不适合表达这类数据,而且由于海量数据的存在,让其显得捉襟见肘.NoSQL数据库的兴起,很好地解决了海 ...

  9. CSAPP(深入理解计算机系统)读后感

    9月到10月8号,包括国庆七天,大概每天5小时以上的时间,把Computer System: A Programmer Perspective 2rd version(深入理解计算机系统)的英文版啃完 ...

随机推荐

  1. 发布订阅--SQLServer复制需要有实际的服务器名称才能连接到服务器,请指定实际的服务器名

    最近在学习SQL SERVER的高级复制技术的时候,遇到一个小问题,就是用本地SQL SERVER连接服务器的数据库时,在查看复制功能的发布服务器时,连接不上,弹出一个错误提示框架,如下: 原来在自己 ...

  2. poj1386单词连接(欧拉欧拉欧拉)

    ///单词连接,欧拉回路通路都可以(有向图) ///主要构图:比如possibilities就构造p->s的边////题目大意:给你若干个字符串,一个单词的尾部和一个单词的头部相同那么这两个单词 ...

  3. Codeforces 1295D Same GCDs

    题目链接 link Solution 这是一道结论题,有两个做法,分别用了欧拉函数或一点点莫比乌斯反演 (这里只放欧拉函数的做法) 设\(d=gcd(m,a)\) \[gcd(\frac{a}{d}, ...

  4. spring02-组件注册-@ComponentScan-自动扫描组件&指定扫描规则

    上一篇我们讲到,讲@Bean注解标在某个方法上,那么ioc容器启动的时候就会将方法返回值放到ioc容器中 在开发中,实际上包扫描用的比较多,接下来我们会介绍两种方式一种是基于xml,一种是基于注解. ...

  5. Hardy-Weinberg laws

    I.3 Diploids with two alleles: Hardy-Weinberg laws 假设子代是Aa,AA,aa的概率分别是PAa,PAA,Paa,A的基因概率是P1,a的基因概率是P ...

  6. C3D使用指南

    C3D GitHub项目地址:https://github.com/facebook/C3D C3D 官方用户指南:https://goo.gl/k2SnLY 1. C3D特征提取 1.1 命令参数介 ...

  7. iMX6Q/PLUS开发板烧写设备树内核的Ubuntu系统

    基于迅为-iMX6D.iMX6Q 和 iMX6PLUS 三个硬件版本,设备树镜像的烧写方法以及镜像所在目录,镜像名称全部一致,所以作者将烧写章节合并到一起. 请注意,如果购买的是 iMX6D 版本,想 ...

  8. 37)PHP,获取数据库值并在html中显示(晋级2)

    下面的是上一个的改进版,我知道为啥我的那个有问题了,因为我的__construct()这个函数的里面的那个变量名字搞错了,哎,这是经常犯得毛病,傻了吧唧,气死我了. 之前的那个变量的代码样子: cla ...

  9. Vscode 下 PlantUML 插件的安装(windows and ubuntu)

    目录 Windows 下安装 JAVA 安装环境配置: 测试 Ubuntu 16.04 下安装 Windows 下安装 Vscode graphviz PlantUML JAVA(推荐长期稳定版本,官 ...

  10. PAT甲级——1011 World Cup Betting

    PATA1011 World Cup Betting With the 2010 FIFA World Cup running, football fans the world over were b ...