运行helloworld程序,计算机做了什么?

#include <stdio.h>
int main(){
    printf("helloworld!");
}

当写下这个程序,点击运行⏯️

这个过程计算机做了什么

一、编译系统

1.1 编译过程

在Unix系统上,由编译器把源文件转化为目标文件

gcc -c -o hello.c hello.o
gcc -o hello.o hello

-o:output

它的具体过程如下:


  • 预处理阶段:处理以 # 开头的预处理命令
  • 编译阶段:翻译成汇编文件;
  • 汇编阶段:将汇编文件翻译成可重定位目标文件
  • 链接阶段:将可重定位目标文件和 printf.o 等单独预编译好的目标文件进行合并,得到最终的可执行目标文件。

1.2 目标文件

  • 可执行目标文件:可以直接在内存中执行;
  • 可重定位目标文件:可与其它可重定位目标文件在链接阶段合并,创建一个可执行目标文件,如静态链接;
  • 共享目标文件:这是一种特殊的可重定位目标文件,可以在运行时被动态加载进内存并链接,如动态链接;

1.3 链接

编译的过程面向的是计算机,链接的过程面向的是人。如果没有链接,人们就不得不每次把需要用到的代码编译一遍,还需要自己在代码中填写相关的物理地址。

链接分为静态链接动态链接

1.3.1 静态链接

静态链接器以一组可重定位目标文件为输入,生成一个完全链接的可执行目标文件作为输出。链接器主要完成以下两个任务:

  • 符号解析:每个符号对应于一个函数、一个全局变量或一个静态变量,符号解析的目的是将每个符号引用与一个符号定义关联起来。
  • 重定位:链接器通过把每个符号定义与一个内存位置关联起来,然后修改所有对这些符号的引用,使得它们指向这个内存位置。

1.3.2 动态链接

静态库有以下两个问题:

  • 当静态库更新时那么整个程序都要重新进行链接
  • 对于 printf 这种标准函数库,如果每个程序都要有printf的代码,这会极大浪费资源

共享库是为了解决静态库的这两个问题而设计的,在 Linux 系统中通常用 .so 后缀来表示,Windows 系统上它们被称为 DLL。它具有以下特点:

  • 在给定的文件系统中一个库只有一个文件,所有引用该库的可执行目标文件都共享这个文件,它不会被复制到引用它的可执行文件中;
  • 在内存中,一个共享库的 .text 节(已编译程序的机器代码)的一个副本可以被不同的正在运行的进程共享

二、操作系统

以中断控制方式为例

2.1 进程的创建

编译系统执行之后,会形成一个hello的可执行文件,windows下后缀是.exe

  1. 用户告诉操作系统执行hello程序

  2. 操作系统到外存找到该程序

  3. 操作系统分配内存,将程序装入内存:当然这个过程当中还涉及到分页的一些内容

  4. 为执行hello程序创建执行环境(创建新进程 )

创建进程的准备工作:操作系统设置CPU上下文环境并跳到程序开始处

这个过程需要的主要寄存器是:

寄存器 含义 作用
PC 程序计数器 存放将要执行的指令地址
IR 指令寄存器 存放正在执行的指令
AC 累加器 临时存储体和累加操作

这里有两个主要问题:

  • 指令:程序的执行并不是一条条语句,而是一条条指令,每条指令执行完CPU会检查是否发生中断

  • CPU上下文:即程序计数器和累加器的值,在发生中断的时候,就要求硬件存储这两个值

2.2 进程的执行

  1. 程序的第一条指令执行
  2. 程序执行与printf对应的库函数、系统调用

产生系统调用,就会陷入内核态,执行内核的read函数

这个时候会提出I/O请求,同时这个hello程序就阻塞了

2.3 进程的阻塞

为什么会阻塞?

因为申请I/O的过程中需要进程等待,驱动程序需要写调用设备的状态寄存器,之后设备控制器需要进行输出的准备。大概过程是:

  1. 操作系统分配设备:需要文件系统的按名访问来获得有关的信息,找到驱动程序
  2. 执行显示驱动程序

在设备控制器进行准备的过程中,CPU调度新的进程来投入运行,这样能提高CPU的利用率,CPU与I/O系统并行工作

2.4 进程的唤醒

I/O完毕之后,CPU接收中断,处理中断,从而唤醒发出I/O请求的进程,这个时候hello进程就转为就绪态。

这个要注意,是就绪态,而不是直接就运行态,CPU处理完中断之后不一定执行hello进程


这个过程需要采用CPU的调度算法

三、计算机硬件

  1. 将像素写入存储映像区(显存)
  2. 视频硬件将像素表示转换成一组模拟信号控制显示器(重画屏幕)
  3. 显示器发射电子束
  4. 显示屏上出现 hello world

在程序的执行过程中还有磁盘读取的一些操作

3.1 磁盘读文件的过程

数据在扇区

  • 逻辑编号,磁盘的逻辑地址转化为物理地址

    每个磁道分为很多扇区,用户文件的数据就存放在扇区上。获得扇区的编号:逻辑编号(也叫做磁盘的逻辑地址)操作系统需要把逻辑编号转换为物理地址。

    物理地址的构成:柱面号:半径相同的构成一个柱面;磁头号;扇区号

  • 送寄存器的相关值

    函数需要得到柱面号、磁头号和起始扇区号。然后将三者放到固定的寄存器中去。一旦启动中断,就开始了硬件上文件的读操作。

    操作系统实质上在做什么?写寄存器、调用中断

3.2 设备控制器

主机I/O系统的结构是:

计算机 ------- I/O通道 -------- 控制器 ---------设备

设备控制器的共性部分:

I/O逻辑需要将命令和地址译码,驱动外设产生动作

参考

[1]:https://github.com/CyC2018/CS-Notes

[2]:https://my.oschina.net/hosee/blog/673628?p=%7b%7bcurrentPage+1%7d%7d

posted @ 2020-05-22 17:25  house_cat  阅读(581)  评论(0编辑  收藏  举报