博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
「深入理解计算系统」从Hello World开始
阅读量:6264 次
发布时间:2019-06-22

本文共 2424 字,大约阅读时间需要 8 分钟。

从 hello world 开始

Table of Contents

1 程序源文件

#include 
int main() { printf ("hello, world\n"); return 0;}

2 程序源文件是什么

程序以0,1串的形式存储在磁盘上,每一个字符有对应的ascii码,每一个ascill码有对应 的0,1串

使用od命令查看源程序ascii码,十进制形式

$ od -Ax -tcd1 hello.c 000000    #    i    n    c    l    u    d    e         <    s    t    d    i    o    .         35  105  110   99  108  117  100  101   32   60  115  116  100  105  111   46000010    h    >   \n   \n    i    n    t         m    a    i    n    (    )         {        104   62   10   10  105  110  116   32  109   97  105  110   40   41   32  123000020   \n                        p    r    i    n    t    f         (    "    h    e         10   32   32   32   32  112  114  105  110  116  102   32   40   34  104  101000030    l    l    o    ,         w    o    r    l    d    \    n    "    )    ;   \n        108  108  111   44   32  119  111  114  108  100   92  110   34   41   59   10000040                        r    e    t    u    r    n         0    ;   \n    }   \n         32   32   32   32  114  101  116  117  114  110   32   48   59   10  125   10000050

3 程序被编译

程序要被机器读懂,需要转换成机器可以读懂的过程,这个过程叫做编译,编译的过程如下

  • 预处理

gcc -E hello.c -o hello.i

这一步实际上将include指令,宏指令等展开

  • 编译

gcc -S hello.i -o hello.s

这一步将宏展开后的文件编译成汇编文件

  • 汇编

gcc -c hello.s -o hello.o
这一步将汇编文件编译成二进制文件

  • 链接

gcc hello.o -o hello

这一步将一些库包含进来,例如我们没有编写printf函数的库,但是却可以使用它的功能。 就是在这一步将其信息包含进来。

4 程序运行

4.1 读取命令

在shell中键入 ./hello 时,首先hello这个字符串要到达内存,这样shell才知道你要执行 什么程序,这个过程有两种方式实现,一个是从键盘到CPU寄存器再到内存的过程,另外一个 是通过直接存储器存取(DMA),不经过CPU直接进入内存。两种方式如下图所示:

4.2 读取指令内容

hello进入内存后,shell知道我们要执行./hello程序,就将磁盘上的hello文件中以二进制 形式存储的机器指令取到内存,再送入CPU执行。

4.3 执行过程

执行的过程是显示"hello world", 这个过程是将这个字符串从内存复制到CPU寄存器,再从 CPU寄存器到达显示设备的过程。

5 进程

5.1 进程切换

操作系统对所有正在运行的程序作了抽象,这种抽象就叫进程。每一个进程都好像是只有 它自己在使用操作系统。而事实上操作系统控制各个进程不停地切换,让每个进程看起来 同时在运行,例如shell与hello两个程序切换过程。

5.2 虚拟地址空间

之所以提出虚拟地址空间的概念是为了简化编程,使得程序看起来独占了整个内存。例如 hello程序的虚拟地址空间如下所示:

Execuable file 区域对应原来磁盘上的二进制hello文件(注意不是源程序,是编译后 的二进制文件),它被完整地映射到了代码和数据区。 Run-time heap 区域是程序运行时动态管理的内存区域,像malloc分配的内存空间就在这一块。 Shared libraries 区域存放的是共享库代码,想一想你同时运行多个程序,它们都包含了 printf函数,这时候printf函数代码就可以被多个程序共享。 User stack 区域用于函数调用,每次调用一个函数时,就把这个函数相关的信息压入栈中, 等函数退出时再弹出栈。 最上面的 Kernel virtual memory区域是内核代码,也为所有程序共享。

特别注意这是一个虚拟地址空间,这些区域在这里看起来是连续的,但是实际在物理内存中 可能就不是连续的了。这只是提供了一种抽象,使得进程之间相互独立,又可以共享一些共 有的东西,操作系统负责将这些虚拟地址映射到实际的物理地址,而程序不直接接触物理 地址,只需要关心虚拟地址就好了。

参考:《深入理解计算机系统》

图片均来自此书电子版。

转载于:https://www.cnblogs.com/Iambda/p/3933480.html

你可能感兴趣的文章
Oracle EBS:打开工作日历查看
查看>>
浅谈字节序(Byte Order)及其相关操作
查看>>
OSG闪存
查看>>
C#迭代器
查看>>
[Android] Change_xml.sh
查看>>
POJ-1925 Spiderman 动态规划
查看>>
实战BULK COLLECT(成批聚合类型)和数组集合type类型is table of 表%rowtype index by binary_integer ....
查看>>
Linux编程基础——线程概述
查看>>
Hive内部表外部表转化分析
查看>>
【转】使用Xcode和Instruments调试解决iOS内存泄露
查看>>
CDE: Automatically create portable Linux applications
查看>>
微信公众平台开发(4)天气预报
查看>>
WPF: RenderTransform特效
查看>>
基础才是重中之重~你是否真正了解TransactionScope?
查看>>
svn
查看>>
何时会发生db file sequential read等待事件?
查看>>
了解你所不知道的SMON功能(十二):Shrink UNDO(rollback) SEGMENT
查看>>
GCC编译器中的扩展
查看>>
[置顶] 礼物:《红孩儿引擎内功心法修练与Cocos2d-x》之结点系统(场景,层,精灵)...
查看>>
使用快捷键,快到极致
查看>>