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

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

通过学习,我们将会知道一些窍门来优化自己的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. org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'socialCode' in 'class java.lang.String'

    异常: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.Refl ...

  2. [CTS2019]随机立方体(容斥+组合数学)

    这题七次方做法显然,但由于我太菜了,想了一会发现也就只会这么多,而且别的毫无头绪.发现直接做不行,那么,容斥! f[i]为至少i个极值的方案,然后这里需要一些辅助变量,a[i]表示选出i个三维坐标均不 ...

  3. Nginx_安全2

    Nginx与安全有关的配置 隐藏版本号 http {    server_tokens off;} 经常会有针对某个版本的nginx安全漏洞出现,隐藏nginx版本号就成了主要的安全优化手段之一,当然 ...

  4. UIView 的Transform属性以及 CGAffineTransform的使用

    什么是Transform? Transform是一个3×3的矩阵,如下图所示: 通过这个矩阵我们可以对一个坐标系统进行缩放,平移,旋转以及这两者的任意组着操作.而且矩阵的操作不具备交换律,即矩阵的操作 ...

  5. iOS 有关二维码

    一.把相应的URL生成二维码 利用有关图像变成的框架 #import <CoreImage/CoreImage.h> 步骤:实例化二维码滤镜---->恢复滤镜属性---->将字 ...

  6. TOJ-2811 Bessie's Weight Problem(DP、背包问题)

    链接:https://ac.nowcoder.com/acm/contest/1082/K 题目描述 Bessie, like so many of her sisters, has put on a ...

  7. PAT甲级——1061 Dating

    1061 Dating Sherlock Holmes received a note with some strange strings: Let's date! 3485djDkxh4hhGE 2 ...

  8. Docker系列五: docker-compose部署Docker容器

    Docker使用Dockerfile来实现对现有镜像的修改来创建新的镜像, 那docker-compose则完成镜像的自动部署, 可以实现多个容器同时部署 Dockerfile可以让用户管理一个单独的 ...

  9. Mysql-win免安装卸载服务后重新安装不能启动的问题

    一.先看配置文件有没有问题,以下是一个简单的配置 [mysql] default-character-set=utf8 [mysqld] character-set-server=utf8 port ...

  10. 常用的SQL优化

    转自:https://www.cnblogs.com/Cheney222/articles/5876382.html 一.优化 SQL 语句的一般步骤 1 通过 show status 命令了解各种 ...