精华内容
下载资源
问答
  •  计算机是由硬件和软件组成的,这两个部分共同协作完成程序运行。这两部分如何协作完成程序运行,是本系列的重点。   信息的表示  信息的表示说到底就是位加上下文。举个小例子,比如11011101这一串二进制...

    计算机的组成

              计算机是由硬件和软件组成的,这两个部分共同协作完成程序的运行。这两部分如何协作完成程序的运行,是本系列的重点。

     

    信息的表示

              信息的表示说到底就是位加上下文。举个小例子,比如11011101这一串二进制,在表示整数的时候它表示221,但是如果放在Java的class文件当中,它可能代表一个JVM的指令。

     

    程序的编译

              对于一个简单的C语言程序来说,一般要经过预处理器、编译器、汇编器和链接器的处理,才能被翻译成一段可执行的二进制文件。

              比如对于一个简单的C语言程序,如下。

    #include <stdio.h>
    
    int main()
    {
         printf("hello,world\n");    
    }

              我们保存在hello.c当中,那么它的翻译过程如下。

    程序的运行 

              程序的运行由解释器负责,它将逐个解释最终生成的二进制文件并执行。

     

    计算机的硬件组成

              首先,我们来看下计算机中硬件的大致分布,如下图。

               其中有几个非常重要的部分,一一看下都是什么作用。

               总线贯穿整个系统的是一组电子管道(其实就是传输数据的线路),也就是总线。总线传送的是字,字的大小与系统相关,比如在32位操作系统当中,一个字是4个字节。

               I/O设备I/O设备是系统与外部联系的通道。I/O设备(键盘、鼠标、显示器等)由控制器(USB控制器)或者适配器(图形适配器,也就是显卡)与I/O总线相连,两者的区别在于一个是主板上的芯片组,一个是主板插槽上的卡。

               主存它是计算机中的一个临时存储设备,在处理器执行程序的时候,主存就是临时存放数据的地方。物理上来说,它是由动态随即存取存储器芯片组成,逻辑上来说,它是一组连续的字节数组,每一个字节都有唯一的地址。

               处理器全称中央处理单元,是解释存储在主存中指令的引擎。处理器的核心是一个程序计数器,它在整个计算机运行的期间都会指向一个主存中的一个内存地址,而地址当中则是一个计算机指令。处理器所做的,就是不停的执行程序计数器所指向的每一条指令。处理器所做的操作是围绕主存、寄存器文件以及算术/逻辑单元进行的,这里面处理器做的最多的动作就是加载(从主存将数据复制到寄存器)、存储(从寄存器将数据复制到主存)、操作(将两个寄存器的内容复制到算术/逻辑单元进行操作,结果会再次复制到寄存器)以及跳转(改变程序计数器当中的内容)。

               处理器当中提到的是指令集结构,不过实际当中指令集的实现是非常复杂的,这么做的目的是为了加速CPU的运算速度。我们可以这样去区分指令集机构以及微体系结构,指令集结构是指令集的抽象描述,而微体系结构则是这个抽象描述的某一个具体实现,类似于JAVA虚拟机与JAVA虚拟机实现的关系。

     

    总结 :计算机是由软件与硬件组成的,而硬件又包括了总线、I/O设备、主存以及处理器,其中信息是由位以及上下文表示的,而信息则是从I/O设备以位的形式通过总线进入主存,然后由处理器从主存将信息取出处理。

               一个程序的执行,是经历了预处理器、编译器、汇编器以及链接器的处理之后,才最终成为可执行的文件。当程序成为可执行文件时就已经保存在了磁盘上,具体的执行过程在下一章再总结。

     

    Hello world的执行

               我们以Linux系统为例,当我们执行一个简单的打印字符串的C程序时,我们需要在命令行输入./hello以及回车去执行该程序。在整个执行过程中,计算机主要做了三件事,或者说经历了三个阶段来完成程序的运行。

     

    1、linux的外壳扫描用户输入的字符

               当我们在键盘输入./hello时,linux的外壳程序(也就是命令行)会扫描我们输入的字符,将这些字符一一读入到寄存器当中,然后再一一放入主存。换句话说,./hello这几个字符是经过了CPU中的寄存器从而到达了主存。下面LZ将这一过程的图示画出来。

     

    2、加载hello文件的代码以及数据到主存

                这一过程的触发是在我们按下回车的那一刻,此时系统会将存储在磁盘上的hello文件加载到主存,而此过程会利用一种叫做存储器存取的技术,使得数据不通过寄存器直接到达主存。下图是这一过程的图示。

     

     

    3、根据主存中代码的指令执行程序

                在代码以及程序所需要的数据加载到主存后,CPU就开始从main函数的起始位置,依次执行代码中的指令。由于我们的代码只是简单的输出“hello world”这样的字符串,因此系统只是将这个字符串依次加载到寄存器,然后传输到显示器终端显示。这个过程如下图。

     

    总结 :本章只是简单的介绍了一下hello程序的执行过程,我们可以简单的这么理解,hello程序的执行,其实就是将数据和代码加载到主存,并由CPU从主存获取指令从而执行的过程。

     

    原文链接:http://www.cnblogs.com/zuoxiaolong/archive/2013/09/20/computer1.html

    展开全文
  • 程序虽然写了不少,但觉得自己对计算机和程序本质的了解依然是小白,偶然间发现了老王的《深入理解计算机系统》,看了目录,如获至宝,是了,这就是我想要的书。可他的是英文版的,理解起来好费劲,所以我入了一本...

    前言

    注:本博客技术文章同步在个人微信公众号(双螺旋炼丹师)发布;

    啊啊啊,好气,兴致勃勃写了一堆前言,结果csdn在线文档卡机了。文档都没存下来。
    好了,也不重新赘述了,大意是虽然我不是码农,非计算机专业出身,但是写程序也是日常工作必备技能。程序虽然写了不少,但觉得自己对计算机和程序本质的了解依然是小白,偶然间发现了老王的《深入理解计算机系统》,看了目录,如获至宝,是了,这就是我想要的书。可他的是英文版的,理解起来好费劲,所以我入了一本中文版的。其实入了有一段时间,一直懒着没看,这周才捡起来细细阅读。
    接下来将会写一系列的读书笔记,内容几乎是参考这本书,但是会根据自己的理解提炼出一些主题,主题涉及的内容次序相比原书本会简练一些,也会加入一些书中没有涉及到的小知识点。

    “Hello,world”是各编程语言的开门语句,那我的第一篇就以“hello,world”为例来说明程序是如何运行的。
    与书本保持一致,本系列文档的编程语言均为C语言。

    本篇内容会分三个部分来介绍程序的运行过程,即,
    计算机系统的硬件组成
    程序的编写和编译
    程序的运行

    计算机系统的硬件组成

    首先,我们来看一下一个典型的计算机系统的硬件组成,如下,
    计算机系统的硬件组成
    接着,我们将逐一说明上图涉及的硬件。

    1)总线

    • 总线贯穿整个计算机系统,对应的实物即为一组电子管,负责在各个部件间传递字节信息。
    • 上图涉及的总线包含:系统总线、内存总线、I/O总线。
    • 总线通常被设计成传送定长的字节块,也就是字。一个字节块/字由多个字节构成,一个字节由8个比特构成。
    • 字节块的长度(即字长,或者字中的字节数)是一个系统的基本参数,如我们常说的32位系统,字长为4个字节,64位系统则为8个字节。

    2)I/O设备
    I/O设备即输入/输出设备,是系统与外部世界的联系通道。
    以上图示包含4个I/0设备,

    • 鼠标和键盘:用于用户输入;
    • 显示器:用于用户输出;
    • 磁盘驱动器:用于长期存数数据和程序。

    3)主存储器

    • 主存储器也就是我们常说的内存,是一个临时存储设备,用来存放要运行的程序和程序处理的数据;
    • 从物理硬件角度,主存储器是一组芯片;
    • 从逻辑角度,主存储器是一个线性的字节数组,每个字节都有其唯一的地址(即从0开始的数组索引)。
      注:为了与日常描述一致,后续主存储器统一描述成内存;

    4)处理器

    • 处理器即是我们常说的CPU,也称“中央处理单元”,是解释(或执行)存储在内存中指令的引擎。
    • PC:此处PC的中文名称为“程序计数器”,是CPU的核心,它是一个大小为一个字的存储设备(或寄存器);在任何时刻,PC都指向内存中的某条机器语言指令。注:从系统通电开始到断电结束,CPU一直在不断地执行PC指向的指令。
    • 寄存器文件:是一个小的存储设备,由一些单个字长的寄存器组成,每个寄存器都有唯一的名字;
    • ALU:也称“算术/逻辑单元”,负责计算新的数据和地址值。

    程序的编写和编译

    程序的编写

    编写程序的第一步当然是创建一份包含源代码的文本文件,以打印“hello,world”为例,

    #include <stdio.h>
    
    int main()
    {
    	Printf(“hello,world!”);
        Return 0;
    }
    
    

    我们通过编辑器创建并保存以上内容,文件命名为hello.c,该文件即为源程序(或者说源文件)。
    在计算机系统中,源程序实际上是一个由0和1组成的位序列(也成为比特序列),8个位构成一组,称为“字节”。一个字节则是上述源程序文本中的一个字符。字符和字节之间的对应关系即是我们常说的的ASCII码表。

    程序的编译

    在C语言中,源文件无法被直接运行,需要被转化成二进制的可执行文件才能行使它的功能,这个转化过程就是我们所说的“编译”。
    Unix系统中,从源文件到可执行文件的转化是由GCC编译器驱动程序完成的:

    gcc  -o hello hello.c
    

    gcc读取hello.c文件内容,并把它翻译成一个可执行目标文件hello。
    该过程由四个阶段构成:预处理器编译器汇编器链接器;该四个过程一起构成了编译系统
    编译系统
    1) 预处理阶段

    预处理器cpp根据以字符#开头的命令,修改原始的程序;

    如我们的hello程序中#开头语句为:#include <studio.h>,cpp读取该内容后会将系统头文件studio.h的内容直接插入到hello.c中,继而形成另一个C程序,即hello.i(一般是以.i作为文件扩展名)

    2) 编译阶段

    编译阶段由编译器ccl完成,ccl将文本文件hello.i翻译成文本文件hello.s

    3) 汇编阶段

    汇编器as将hello.s翻译成机器语言二进制指令,并把这些内容打包成一种叫做可重定位目标程序的格式,结果保存在hello.o中。

    hello.o包含了main程序要执行的指令编码。

    4) 链接阶段
    链接器ld的作用是合并程序中用到的其他函数的指令,得到最终的可执行目标程序/文件
    如,

    • hello程序调用了printf函数;
    • printf是C语言的标准库中的函数,存在一个名为printf.o的独立预编译目标文件中;
      链接器ld需要将printf.o合并到hello.o文件中,最终得到可执行目标文件hello

    程序的运行

    第二步中终于准备好了可执行文件hello,该文件可以被加载到内存中,由系统执行。
    程序的运行分三步执行:
    1) 系统从键盘读取命令
    用户通过键盘在shell终端输入”./hello”时(未按回车键),shell程序将字符逐一读入寄存器,并将它放入缓存中。
    下图黑色加粗线条展示了该过程的数据流向,蓝色背景方框表示该过程涉及的硬件。
    系统从键盘读取hello命令

    2) 系统从磁盘加载可执行文件到内存
    当我们在键盘上敲下回车键时,shell程序认为我们已经结束了命令的输入;
    紧接着,shell执行指令从磁盘存储中读取可执行文件hello,将文件中的代码和数据从磁盘复制到内存。
    从磁盘加载可执行程序到内存
    3) 系统执行可执行文件内容并输出到终端显示器
    当可执行文件hello中的代码和数据被加载到内存,处理器开始执行程序中的main程序中的机器语言指令。
    这些指令将”hello,world\n”字符串中的字节从内存复制到寄存器文件,再从寄存器文件复制到显示设备,最终在显示屏上呈现”hello,world”字符。
    将输出字符串从存储器写到显示器
    注:文中图片均系本人在PPT中绘制;

    那么以上就是hello程序运行的实际过程,希望你看完这篇对自己程序的运行过程有了更深的印象和感受。

    <End>

    展开全文
  • 【深入理解计算机系统程序是如何运行的 1、首先我们来了解一下什么是程序 程序是为求解某个特定问题而设计的指令序列。程序中的每条指令规定机器完成一组基本操作。如果把计算机完成一次任务的过程比作乐队的一次...


    【深入理解计算机系统】程序是如何运行的
    1、首先我们来了解一下什么是程序
            程序是为求解某个特定问题而设计的指令序列。程序中的每条指令规定机器完成一组基本操作。如果把计算机完成一次任务的过程比作乐队的一次演奏,那么控制器就好比是一位指挥,计算机的其它功能部件就好比是各种乐器与演员,而程序就好像是乐谱。计算机的工作过程就是执行程序的过程,或者说,控制器是根据程序的规定对计算机实施控制的。

            简单来说:程序就是指令的集合,为使计算机按预定要求工作,首先要编制程序。程序是一个特定的指令序列,它告诉计算机要做哪些事,按什么步骤去做。指令是一组二进制信息的代码,用来表示计算机所能完成的基本操作。

    2、程序是如何运行的
           现代计算机存储和处理的信息以二值信号表示,程序对于计算机而言就是一串二进制数据流,以流水线的方式进入CPU进行运算。主要在;CPU与内存之间进行数据传递。本文将从程序源码的结构与表现形式开始,到编译生成可执行文件,再到执行文件的加载,最终到执行文件的运行整个过程进行梳理。

    3、计算机程序执行过程

    1.将程序翻译成机器可读的格式

    因为我们输入的hello, world程序是人可读的,机器并不能直接识别它们。我们需要把这些文字翻译成机器可执行的二进制文件。这一部分的工作是由编译系统完成的。编译系统由预处理器、编译器、汇编器、连接器四部分组成。以hello, world程序为例,各部分共同完成将源文件编译成二进制可执行文件。各个部分完成的具体工作如下:

    l 预处理器:根据以#开头的命令,修改源程序。如根据#include <stdio.h>行,预处理器读取系统头文件stdio.h中的内容,代替此行内容。源程序经过预处理后,得到另一个c程序,此程序通常以.i为后缀保存。

    l 编译器:将预处理后的.i文件转换成汇编程序。编译器将不同的高级语言(如c语言,C++语言)转换成严格一致的汇编语言格式进行输出。汇编语言以标准的文本格式确切的描述每机器语言指令。编译器得到的文件通常以.s为后缀保存。

    l 汇编器:将汇编语言(.s文件)翻译成机器语言指令,并将这些指令打包成一种可定位目标程序格式。汇编后得到的文件即为二进制文件,通常以.o为后缀。

    l 链接器:hello, world程序中调用过printf函数,它是一个c标准库里的函数。Printf函数存放在一个名为printf.o的单独预编译的文件中。而这个文件必须以适当的方式并入到我们的程序中,这个工作由链接器完成。将外部的.o文件并入后,得到一个完整的hello, world可执行文件。可执行文件加载到存储器后,由系统复制执行。

    编译系统

    在linux系统上,输入编译命令行:

    Viidiot>gcc hello.c -o hello

    将执行上图所示的四个步骤,得到可执行二进制文件hello。

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

    Shell:命令行解释器,为用户提供了一只与系统打交道的方式。它等待用户的输入,当用户输入一行命令后,shell先判断它是不是一个shell内置命令,如果不是,shell会假定用户输入为一个可执行文件的名字,从而去加载并执行该文件。因此,当我们通过编译系统将源文件编译成可执行二进制文件后,在shell中输入我们得到的可执行二进制文件名,shell将其从磁盘中加载到存储器(注:我们的可执行文件是存放在磁盘上的),并通过处理器进行解释执行,得到最终的结果,输出到终端(显示器)上进行显示。自此,我们的hello, world程序完成了其生命周期。

    4.计算机系统硬件结构

    为了弄清楚hello, world运行时,系统究竟发生了什么,我们先来了解下一个典型的计算机硬件结构。

    图3 典型的计算机硬件构成

    【CPU:中央处理器   ALU:算术/逻辑运算单元  PC:程序计数器  USB:统一串行接口】

    下面简单说一下各个部件在系统中所起的作用。

    总线:在各个部件之间传输数据。现在的总线宽度一般为32位或者64位,即一次传输的数据为4字节或者8字节。

    I/O设备:IO设备是系统与外界通信的通道,如鼠标,键盘,显示器都是典型的IO设备。

    主存储器:简称主存,是处理器执行程序时用于临时存放程序及其数据。主存由一组动态随机存储器芯片组成。

    处理器:解释执行存储在主存中的指令。其内部包含一个双字节程序计数器(PC),任何时候PC中都存放着接下来要执行的机器指令在主存中的地址。

    处理器的操作主要是围绕PC、ALU、主存来进行运作的。处理器首先从PC所指向的主存存储单元读取指令,解释指令中的位,执行该指令指示的简单操作,然后更新PC寄存器,使其指向下一条要执行的指令。CPU会执行的操作有:

    加载:把一个字节或一个字从主存复制到寄存器,覆盖掉寄存器中原来的值。

    存储:把一个字节或一个从寄存器复制到主存,并覆盖主存中原来的值。

    操作:把两个寄存器的内容复制到ALU,ALU对两个字做算术运算后存回其中的一个寄存器,该寄存器中原来的值会被覆盖。

    跳转:从cpu执行的指令抽取一个字的内容存入PC,覆盖掉原来的值,从而改变下一条要执行的指令,达到跳转的目的。

    在了解了一些基本的硬件结构,以及各个部分的作用后,我们再来看看之前的hello, world程序的运行过程。

     加载可执行文件到主存的过程

    在linux系统下,我们在shell中敲入以下命令

    Viidiot>./hello

    由于shell没有内置hello命令,因此shell将我们输入的hello视为一个可执行文件,从而通过执行一系列机器指令,将可执行文件hello从磁盘复制到主存,如图4所示。

    注意,如果通过DMA方式加载程序,则不需要通过CPU,而是将hello可执行文件直接从磁盘复制到主存,示意图如图5。

    DMA方式加载程序到主存

    可执行程序加载到主存后,cpu就执行hello程序的机器指令,而这些指令完成的工作便是将”hello,world\n”这几个字符从主存中复制寄存器文件中(register file),再将其从寄存寄文件中复制到显示设备上进行显示。过程示意图如图6所示。

      cpu执行指令,将 “hello,world\n”从内存复制到显示设备

    至此,hello,world程序的执行过程已经完成。

    题外话:

    从上面的程序实例我们可以看到,程序花费了大量的时间将数据从一个部件复制到另外一个部件。程序加载时,将hello程序的机器指令从磁盘复制到主存,程序运行时,又将其从主存复制到cpu,最后又从cpu复制到外部显示器。将根据机械原理,大容量的存储设备速度比小容量存储设备慢,快速设备的造价比慢速设备的造价高。对于计算机硬件系统,CPU的速度远高于主存的速度,而主存的速度远高于磁盘,不同部件的速度严重不对等,从而快的设备的性能没能得到充分发挥。为解决各类设备速度不匹配的问题,引入了高速缓存设备来缓解速度匹配问题。如图7所示,为加入了高速缓存后的系统部分结构。

    高速缓存存储器

    现代计算机为提高系统性能,一般都加入了多级缓存结构。高速缓存采样的是静态随机存储器硬件(SRAM)技术,速度快于主存(采样动态随机存储器技术)。如图8是存储器结构金字塔,越往上速度越快,造价也更昂贵。

     存储器金字塔

    4.程序的结构与表现形式
            大多数计算使用8位的块,即字节(byte),作为最小的可寻址的内存单元。程序对象,即程序数据、指令和控制信息的字节集合,编译器和系统运行时将存储空间划分成更可管理的单元来存储程序对象。

    计算机执行机器代码,用字节序列编码低级的操作,包括处理数据、管理内存、读写存储设备上的数据、以及利用网络通信。程序源码会经过编译器生成机器代码,编译器基于编程语言的规则、目标机器的指令集合和操作系统遵循的惯例,经过一系列的阶段生成机器代码。汇编代码是机器代码的文本表示,给出程序中的每一条指令。

    计算机系统使用了多种不同形式的抽象,利用抽象模型来隐藏实现的细节。对于机器级编程来说,两个重要的抽象:
    1. 指令集架构(Instruction Set Architecture, ISA) 定义机器级别格式和行为,处理器状态、指令的格式,以及每条指令对状态的影响。
    2. 虚拟内存地址,程序使用的内存地址是虚拟地址,提供内存模型看上去是一个非常打的字节数组。实际上又许多个硬件存储器和操作系统软件组合起来。

    以C语言为例,编写程序mstore.c

    long mult2(long, long);

    void multistore(long x, long y, long *dest) {
        long t = mult2(x, y);
        *dest = t;

    经过gcc编译器,产生一个汇编文件mstore.s

    multstore:
        pushq %rbx
        movq %rdx, %rbx
        call mult2
        movq %rax, (%rbx)
        popq %rbx
        ret
    上面代码中每行对于一条机器指令,比如, pushq指令应该将%rbx的内容压入程序栈中。

    再将改mstore.c编译并汇编成目标代码文件mstore.o,该二进制文件中,又一段14个字节的序列,它的十六进制表示为:

    53 48 89 d3 e8 00 00 00 00 48 89 03 5b c3
    为了弄清这些14个字节表示的含义,可以通过objdump 反汇编 该mstore.o 文件
    可以看到,这14个字节分成若干组,左边是一条指令,右边是等价的汇编语言。

    程序中包含过程、控制

    过程
           是软件中一种重要的抽象。它提供了一种封装代码的方式,用一组制定的参数和一个可选的返回值实现了某一功能。然后,可以再程序中不同的地方调用这个函数。设计良好的软件用过程作为抽象机制,隐藏某个行为的具体实现,同时又提供清晰简洁的接口定义,说明计算的是哪些值,过程会对程序状态产生什么样的影响。不同编程语言中,过程的形式多样;函数(funciton)、方法(method)、子例程(subroutine)、处理函数(handler)等等。

    要提供对过程的机器级支持,必须要处理许多不同的属性。为了讨论方便,假设过程P调用过程Q,Q执行后返回到P。这些动作包括一下一个或多个机制:

    传递控制。再进入过程Q的时候,程序计数器必须被设置位Q的代码的起始地址,然后在返回时,要把程序计数器设置位P中调用Q后面那条指令的地址。
    传递数据。P必须能够向Q提供一个或多个参数,Q必须能够向P返回一个值
    分配和释放内存。在开始时,Q可能需要为局部变量分配空间,而在返回前,又必须释放这些存储空间。
    x86-64的过程实现包括一组特殊的指令和一些对机器资源(寄存器和程序内存)使用的约定规则。

    控制
            程序中的控制逻辑,例如条件语句if else, 循环for do-while等。机器级指令的执行,有两种方式实现条件控制,一种将控制条件进行传递,一种是将不同条件计算结构进行传递。后一种方式在现代计算机中能提高程序运行的效率,代码中的指令都是按照在程序中出现的次序,顺序执行的,使用jump指令可以改变一组机器代码指令的执行顺序,从而实现条件操作。

    为了实现条件控制,CPU中维护了一组单个位的条件码(condition code) 寄存器,它们描述了最近的算数或逻辑操作的属性。可以通过检测这些寄存器来执行条件分支指令,通常条件码有,CF:进位标志;ZF:零标志。SF: 符号标志;OF:溢出标志。

    运行时调用栈

    大多数语言过程调用机制采用栈数据结构提供的后进先出的内存管理原则。过程P调用过程Q的过程,如果上图所示。è¿éåå¾çæè¿°

    5、程序代码的编译过程

    è¿éåå¾çæè¿°
    预处理阶段,主要是修改原始程序,例如将#include<stdio.h> 命令告诉预处理读取系统stdio.h的文件,并将它直接插入到程序文本中。结果得到的另一个C程序,以.i作为扩展名;
    编译阶段,编译器ccl将文本hello.i翻译成文本hello.s,它包含一个汇编语言程序;
    汇编阶段,汇编器将.s文件编译成一个二进制的文件,把这些指令打包成一种叫做可重定位的目标程序的格式,并将结果保存在目标文件.o文件中。
    链接阶段,将各种代码和数据片段手机并组合并成可以执行的目标文件,简称可执行文件,可以被加载到内存中,由系统执行。

    本节主要讨论链接阶段。链接可以执行与编译时,即将源代码翻译成机器代码时;可以执行与加载时,即程序被加载器加载到内存时;可以执行与运行时,也就是由应用程序来执行。

    链接器是的分离编译(separate compilation)成为可能。我们不用将一个大型的应用程序组织成一个巨大的源文件,而时可以把它分解为更小、更好管理的模块。理解链接的工作原理可以帮助我们避免一些危险的编程错误、理解语言的作用域规则、理解一些重要概念(加载、运行程序、虚拟内存、分页、内存映射)、有助于理解共享库。

    为了构造可执行的文件,链接器必须完成两个主要任务:

    符号解析(symbol resolution)。 目标文件定义和引用符号,每个符号对应于一个函数、一个全局变量或一个静态变量。符号解析的目的时将每个符号引用正好和一个符号定义关联起来;
    重定位(relocaiotn)。编译器和汇编器生成从地址0开始的代码和数据节。链接器通过把每个符号定义与一个内存位置关联起来,从而重定位这些节,然后修改所有对这些符号的引用,使得他们指向内存这个内存位置。链接器使用汇编器产生的重定位条目(relocation entry)的详细指令,不加甄别地执行这样的重定位。
    目标文件分为三种:

    可重定位目标文件,包含二进制代码和数据,其形式在编译时可以与其他可重定位目标文件合并起来,创建一个可执行目标文件;
    可执行目标文件,包含二进制代码和数据,其形式可以被直接复制到内存并执行;
    共享目标文件,一种特殊类型的可重定位目标文件,可以在加载或者运行时被动态地加载进内存并链接。
    3 执行文件
    可执行的目标文件,通过加载器,加载到内存,共CPU调用运行。

    进程是执行中程序的一个具体实例,程序总是运行在某个进程的上下文中。

    进程提供了给应用程序的关键抽象:

    1.一个独立的逻辑控制流,程序计数器PC值序列叫做逻辑控制流,每个PC值对应可执行目标文件中的指令,或者是包含在运行是动态链接到程序的共享对象中的指令。
    2.一个私有的地址空间,进程位每个程序提供一种假象,好像它独占地使用系统地址空间。例如,在一台64位地址的机器上,地址空间是264264 个可能地址的集合。进程为每个程序提供它自己的私有地址空间。一般而言,其他进程是不能访问该进程的地址空间所关联的内存字节。
    每个私有地址空间有相同通用的结构,如下图所示è¿éåå¾çæè¿°

    地址空间底部是保留给用户程序的,包括通常的代码、数据、堆和栈段。代码段总是从地址0x00400000开始。地址空间顶部保留给内核(操作系统常驻内存的部分)。地址空间的这部分包含内核在代表进程执行指令时使用的代码、数据和栈。
    为了使操作系统内核提供一个无懈可击的进程抽象,处理器必须提供一种机制,限制一个应用可以执行的指令以及它可以访问的地址空间范围。处理器通常是用某个控制寄存器的一个模式为来提供这种功能,该寄存器描述了进程当前享有的特权。

    进程运行有两种模式:
    1. 内核模式(超级用户模式)
    2. 用户模式

    当设置了模式位时,进程就运行在内核模式中(超级用户模式)。一个运行在内核模式的进程可以执行指令集中的任何指令,并且可以访问系统的任何内存位置。

    没有设置模式位时,进程运行在用户模式中。用户模式中的进程不允许执行特权指令(privileged instruction),比如停止处理器、改变模式位、或者发起一个I/O操作。也不允许用户模式中的进程直接引用地址空间中内核区内的代码和数据。任何这样的尝试都会导致致命的保护故障。反之,用户程序必须通过系统调用接口间接地访问内核代码和数据。

    操作系统内核使用一种称为上下文切换的较高层形式的异常控制流来实现多任务。内核为每个进程维持一个上下文明。上下文就是内核重新启动一个被抢占的进程所需状态。进程切换包含三个操作

    1.保存当前进程的上下文
    2.恢复某个先前被抢占的进程被保存的上下文
    3.将控制传递给这个新恢复的进程

    è¿éåå¾çæè¿°
    当进程A开始读取磁盘文件时,会通过执行系统调用read陷入到内核。内核中的陷进处理程序请求来自磁盘控制器的DMA传输,并且安排在磁盘控制器完成从磁盘到内存的数据传输后,磁盘终端处理器。

    每个执行的程序,即系统中的进程,进程总可以处于下面三种状态:

    1.运行,进程要么在CPU上执行,要么在等待被执行且最终会被内核调度;
    2.停止,进程的执行被挂起,且不会被调度,当收到SIGSTOP、SIGTSTP、SIGTTIN或者SIGTTOU信号时,进制就会停止,并且 保持停止知道它收到一个SIGCONT信号,在这个时刻,进程再一次开始运行。
    3.终止,进程永远地停止了。进程会因为三种原因终止:1)收到进程终止的信号,2)从主程序返回;3)调用exit函数。
    加载并运行程序

    当使用execve函数在当前进程的上下文中加载并运行一个新程序。
    (fork是在父进程下,创建一个新的上下文运行子进程)

    #include <unistd.h>
    int execve(const char *filename, const char *argv[], const char *envp[]);
    当使用execve加载filename之后,启动代码设置栈,并将控制传递给新程序的主函数。
    用户栈的典型组织结构:

    信号
    除了操作系统利用异常来支持进程上下文切换的异常控制流形式,另外一种更高层次的软件形式的异常,成为Linux信号,它运行进程和内核中断其他进程。

    一个信号就是一条小消息,它通知进程系统中发生了一个某种类型的事件。每种信号类型都对应于某种系统事件。底层的硬件异常是由内核异常处理程序处理的,正常情况下,对于用户进程而言是不可见的。信号提供了一种机制,通知用户进程发生了这些异常。比如,当进程在前台运行时,你键入Ctrl+C,那么内核就会发送一个SIGINT信号强制终止它。当一个子进程终止或者停止时,内核会发送一个SIGCHLD信号给父进程。

    传送一个信号到目的进程是由两个不同步骤组成的

    发送信号,内核通过更新目的进程上下文种的某个状态,发送一个信号给目的进程。发送信号可以由如下两种原因:1)内核检测到一个系统事件,比如除零错误。2)一个进程调用kill,显示要求内核发送一个信号给目的进程。一个进程可以发送信号给它自己
    接受信号,当目的进程被内核强波以某种方式对信号的发送做出反应时,它就接收了信号。进程可以忽略这个信号,终止或者通过之心一个称为信号处理程序的用户曾函数捕获这个信号。
    一个发出而没有被接收的信号,叫做处理信号,在任何时刻,一种类型至多只会由一个待处理信号。重复发送在等待的信号,将会被内核抛弃。
    linux 提供两种阻塞机制,隐式和显式

    1.隐式,即内核默认会阻塞当前处理程序接受到的待处理信号,正好与该待处理信号类型相同的信号已经被该处理程序所捕获。
    2.显示阻塞机制,应用程序可以使用singprocmask函数和它的辅助函数,明确地阻塞和解除阻塞选定的信号。
     

    展开全文
  • 能接收***处理机的命令,独立执行通道程序,协助***处理机控制与管理外部设备。一个独立于CPU的专门I/O控制的处理机,控制设备与内存直接进行数据交换。它有自己的通道命令,可由CPU执行相应指令来启动通道,并在...

    通道是独立于CPU的、专门负责数据共享以及传输工作的处理单元。

    通道是计算机系统中传送信息和数据的装置。主要有主存储器读写通道和输入、输出通道。能接收***处理机的命令,独立执行通道程序,协助***处理机控制与管理外部设备。一个独立于CPU的专门I/O控制的处理机,控制设备与内存直接进行数据交换。它有自己的通道命令,可由CPU执行相应指令来启动通道,并在操作结束时向CPU发出中断信号。通道指令的格式一般由:操作码,记数段,内存地址段,结束标志组成。一个系统中可设立三种类型的通道:字节多路通道、数组多路通道、选择通道.

    通道的出现则进一步提高了CPU的效率.这是因为通道是一个特殊功能的处理器.它有自己的指令和程序专门负责数据输入输出的传输控制.而CPU将“传输控制”的功能下放给通道后只负责“数据处理”功能.

    3.单处理机计算机:在计算机体系结构中,处理机就是CPU,单处理机计算机系统中某个时刻只有一个程序在使用CPU运行,通过进程调度可以实现宏观上的多程序并行的效果,但微观上仍然是串行的。具有多个CPU的计算机系统中,某一时刻每个CPU中都可以有一个程序在运行,可以实现真正意义上的并行。

    展开全文
  • 本章通过跟踪hello程序的生命周期来开始对计算机系统进行学习。一个源程序从它被程序员创建开始,到在系统上运行,输出简单的消息,然后终止。我们将沿着这个程序的生命周期,简要地介绍一些逐步出现的关键概念、...
  • 思维导图: 引言: 深入理解计算机系统系列是我看<<深入理解设计系统>... 计算机系统是如何执行程序代码的 一.计算机系统的组成 计算机系统是由硬件和系统软件组成的,他们共同工作来运行引用...
  • 【深入理解计算机系统程序是如何运行的 1、首先我们来了解一下什么是程序 程序是为求解某个特定问题而设计的指令序列。程序中的每条指令规定机器完成一组基本操作。如果把计算机完成一次任务的过程比作乐队的一...
  • 关于《深入理解计算机系统》 “这本书的中译名为“深入理解计算机系统”,我非常,十分,以及百分之一百二十地不满意。我这么说的原因在于这个译法完全扭曲了书的本意。如果直译原书名,应该是类似于“以程序员的...
  • 计算机系统结构总复习

    万次阅读 多人点赞 2019-01-08 08:27:31
    计算机系统结构基础及并行性的开发 计算机系统的层次结构 通用计算机系统可以被可以被看出是按机器级划分的多层机器级组成的层次结构。 语言应用机器级 高级语言 汇编 操作系统 传统机器语言 微程序机器级 机器:...
  • 汇编3-计算机程序是如何运行

    万次阅读 2018-01-04 21:59:20
    1.引言 前面我们已经提到过寄存器以及cpu的一些基本工作原理,那么在一个程序运行时,寄存器...本文会尽可能详细地描述从写一个源程序到它被执行的过程中都计算机内部都发生了哪些事情。 2.计算机是如何工作的呢
  • 感觉自己对计算机系统的整体把握不够,所以找来这本书学习一下,读书要做笔记,第一章,开始。 书名:Commputer Systems (A Programmer's Perspective Second Edition) 深入理解计算机系统 站在程序员的视角讲...
  • 第1章 计算机系统结构的基本概念 1. 什么是计算机系统的多级层次结构?从计算机语言的角度,把计算机系统按功能划分成以下多级层次结构: 2. 硬件和软件在什么意义上是等效的?在什么意义上是不等效的?硬件和软件...
  • 第1章 计算机系统结构的基本概念 多级层次结构从计算机语言的角度,把计算机系统按功能划分成多级层次结构。 虚拟机器由软件实现的机器。 解释语言实现的一种基本技术。每当一条N+1级指令被译码后,就直接去执行一...
  • 概括的讲计算机系统是由硬件和系统软件共同组成的,它们通过共同的协作来运行应用程序。而我们在日常编写程序时使用的文件、内存、进程等概念都是为了程序编写的方便,由实际的计算机系统高度抽象而来。这一章中我们...
  • 文章目录第一章 计算机系统概述1.1 操作系统的基本概念1.1 练习题1.2 操作系统的发展与分类1.2 练习题1.3 操作系统的运行环境1.3 练习题1.4 操作系统的体系结构1.4 练习题 第一章 计算机系统概述 1.1 操作系统的基本...
  • 计算机系统概述

    千次阅读 2018-09-28 09:09:59
    2.采用存储程序的工作方式。   现代计算机采用数字化存储信息,利用物理表示较为容易,例如:用电平高低表示0和1,或用脉冲有无表示0和1。   信息数字化的好处: 1。物理上易表示存储; 2抗干扰能力强,可靠...
  • 关于《深入理解计算机系统》 “这本书的中译名为“深入理解计算机系统”,我非常,十分,以及百分之一百二十地不满意。我这么说的原因在于这个译法完全扭曲了书的本意。如果直译原书名,应该是类似于“以程序员的...
  • 进程(Process)一个执行中的程序的实例,操作系统对一个正在运行程序的一种抽象。并发运行,指的是一个进程的指令和另一个进程的指令交错执行。操作系统实现这种交错执行的机制称为上下文切换。 线程(Thread) ...
  • 软件:各种程序和文件,用于指挥计算机系统按指定的要求进行协同工作 包括系统软件、支撑软件和应用软件 关键系统软件是:操作系统与语言处理程序 计算机硬件系统的组成 中央处理器 运算单元 控制单元 ...
  • 深入理解计算机系统-笔记

    万次阅读 多人点赞 2017-12-14 13:00:43
    计算机系统漫游 程序  程序的生命周期从一个源程序(源文件)开始,即程序员利用编辑器创建并保存的文本文件,如文件名为hello.c的c语言程序。源程序是由0和1组成的位序列,8个位被组织成一组,称为字节。每个...
  • 为了解在计算机系统中,程序是如何运行的,首先需要了解计算机系统的硬件组织。 1、总线 总线是贯穿整个系统一组电子管道,它携带信息字节并负责在各个部件间传递。通常总线被设计成传送特定长的字节块,也就是...
  • 计算机系统总线

    千次阅读 多人点赞 2016-11-08 11:56:05
    申明:这篇文章是我学习了哈尔滨工业大学计算机科学与技术系刘宏伟老师的mooc课程(参考教材为高教出版社出版的唐朔飞老师编写的《计算机组成原理(第二版)》)的课堂笔记整理,其中的截图来自刘宏伟老师上课的PPT...
  • 在现实生活中,在不同行业中,我们经常处理设计用于多种用途的系统,以执行单一类型的任务。 此时发生的流程称为需求服务,而系统本身称为排队系统。 本文致力于对相关系统中发生的过程进行计算机软件建模,尤其是...
  • 计算机基础原理-程序是怎么运行

    万次阅读 2018-04-14 15:11:47
    信息在计算机的中表示我们输入以下程序,编译运行计算机从屏幕输出hello, world。整个过程计算机都怎么运作的呢?#include &lt;stdio.h&gt;int main(){printf("hello, world\...
  • 计算机系统概论

    千次阅读 2017-09-20 14:21:27
    (二)计算机系统层次结构 1.计算机系统的基本组成 2.计算机硬件的基本组成 3.计算机软件的基本组成 4.计算机系统的工作过程 (三)计算机性能指标 —吞吐量、响应时间; —CPU 时钟周期、主频、CPI、CPU...
  • 1.1 计算机系统的层次结构 从使用语言的角度,一台由软、硬件组成的通用计算机系统可以被看成是按功能划分的多层机器级组成的层次结构。具体的计算机系统,其层次数的多少可以有所不同。 说明: M0用硬件实现...
  • 计算机OS是如何运行程序

    千次阅读 2016-03-23 10:16:02
     计算机是由硬件和软件组成的,这两个部分共同协作完成程序运行。这两部分如何协作完成程序运行,是本系列的重点。   信息的表示  信息的表示说到底就是位加上下文。举个小例子,比如11011101这一串...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 71,033
精华内容 28,413
关键字:

当计算机系统执行通道程序