第一章 引言
让我最有收获的内容:
1.8 关于Unix
Unix是一种通用操作系统。
开发者:肯·汤普森(Ken Thompson)和丹尼斯·里奇(Dennis Richie)
诞生日期:20世纪70年代早期
经典书目:K&R 1988 《The C Programming Language》
1.9 关于Linux
Linux(Linux 2017)是一个类Unix系统。它最初是Linus Torvalds在1991年为基于Intel x86的个人计算机开发的一个实验性内核。
Linux的一个重要里程碑发生在20世纪90年代末,当时,它与GNU(Stallman 2017)相结合,纳入了许多GNU软件,如GCC编译器、GNU emacs编辑器和bash等,极大地促进了Linux的进一步发展。不 久之后,Linux实现了访问互联网的TCP/IP协议族,并移植了支持GUI的X11(X-window),成为一个完整的操作系统。
Linux包含其他Unix系统的许多特性。在某种意义上,它是由各种最为流行的Unix系统组合而成。在很大程度上,Linux是兼容POSIX标准的。Linux已被移植到许多硬件体系结构中,如摩托罗拉、SPARC和ARM等。主要的Linux平台仍然是基于Intel x86的个人计算机,包括广泛可用的台式机和笔记本电脑。此外,Linux可免费使用,且易于安装,因此,颇受计算机科学专业的学生欢迎。
1.13 使用Linux
1.13.1 Linux内核镜像
在典型的Linux系统中,Linux内核映像位于/boot目录中。可启动的Linux内核映像名为vmlinuz-generic-VERSION_NUMBER
initrd是Linux内核的初始的ramdisk映像。
一个可启动的Linux内核映像由三部分组成:
| BOOT | SETUP | linux kernel
BOOT是一个512字节的启动程序,用于从软盘映像启动早期的Linux版本。但现在,它不再用于Linux启动,而是包含一些参数,以供“SETUP”使用。SETUP是一段16位和32位的汇编代码,用于在启动期间将16位模式转换为32位保护模式。linux kernel是Linux的实际内核映像。它采用压缩格式,但在开始时有一段解压代码,用于解压Linux内核映像并将其放入高端内存中。
1.13.2 Linux启动程序
Linux内核可以由几个不同的启动加载程序启动。最受欢迎的Linux启动加载程序是GRUB和LILO。另外,HD启动程序(Wang 2015)也可用来启动Linux。
1.13.3 Linux启动
在启动期间,Linux启动加载程序首先会定位Linux内核映像(文件)。然后:
- 加载BOOT+SETUP至实模式内存的0x90000处。
- 加载Linux内核至高端内存的1MB处。
对于常见的Linux内核映像,该加载程序还会将初始ramdisk映像initrd加载到高端内存中。然后转移控制权,运行0x902000处的SETUP代码,启动Linux内核。首次启动时,Linux内核会将initrd作为临时根文件系统,在initrd上运行。Linux内核将执行一个sh脚本,该脚本指示内核加载实际根设备所需的模块。当实际根设备被激活并准备就绪时,内核将放弃初始ramdisk,将实际根设备挂载为根文件系统,从而完成Linux内核的两阶段启动。
1.13.4 Linux运行级别
Linux内核以单用户模式启动。它可以模仿System V Unix的运行级别,以多用户模式运行。然后,创建并运行INIT进程P1,后者将创建各种守护进程和供用户登录的终端进程。之后,INIT进程将等待任何子进程终止。
1.13.5 登录进程
各登录进程将在其终端上打开三个文件流:stdin(用于输入),stdout(用于输出),stderr(用于错误输出)。然后等待用户登录。在使用X-window作为用户界面的Linux系统上,X-window服务器通常会充当用户登录界面。用户登录后,(伪)终端默认属于用户。
1.13.6 命令执行
登录后,用户进程通常会执行命令解释程序sh,后者将提示用户执行命令。sh将直接执行一些特殊命令,如cd(更改目录)、exit(退出)、logout(注销)、&。
1.14 使用Ubuntu Linux
1.14.2 Ubuntu Linux的特性
(1)在台式机或笔记本电脑上安装Ubuntu时,需要输入用户名和密码来创建一个默认主目录为“/home/username”的用户账户。当Ubuntu启动时,它会立即在用户环境中运行,因为其已自动登录默认用户。
(2)出于安全原因,用户应为普通用户,而不是根用户或超级用户。
要运行任何特权命令,用户必须输入
sudo command
(3)用户的“PATH”(路径)环境变量设置通常不包括用户的当前目录。为在当前目录下运行程序,用户每次必须输入./a.out。为方便起见,用户应更改路径设置,以包含当前目录。在用户的主目录中,创建一个包含以下代码的.bashrc文件:
PATH=$PATH:./
用户每次打开伪终端时,sh都会先执行.bashrc文件来设置路径,以包含当前工作目录。
(4)很多用户可能都安装了64位的Ubuntu Linux。本书中的一些编程练习和作业是针对32位机器的。在64位Linux下,使用
gcc -m32 t.c # compile t.c into 32-bit code
生成32位代码。若64位Linux不采用-m32
选项,则用户必须安装适用于gcc的附加支持插件,才能生成32位代码。
(5)Ubuntu具有友好的GUI用户界面。许多用户都习惯于使用GUI,以至于产生了过度依赖,这往往需要反复拖动和点击指向设备,从而浪费了大量时间。在系统编程中,用户还需要学习如何使用命令行和sh脚本,它们比GUI要通用和强大得多。
1.15 Unix/Linux文件系统组织
1.15.3 Unix/Linux命令
Unix/Linux中最常用的命令:
- ls:ls dirname:列出CWD或目录的内容。
- cd dirname:更改目录。
- pwd:打印CWD的绝对路径名。
- touch filename:更改文件名时间戳(如果文件不存在,则创建文件)。
- cat filename:显示文件内容。
- cp src dest:复制文件
- mv src dest:移动或重命名文件。
- mkdir dirname:创建目录。
- rmdir dirname:移除(空)目录。
- rm filename:移除或删除文件。
- ln oldfile newfile:在文件之间创建链接。
- find:搜索文件。
- grep:搜索文件中包含模式的行。
- ssh:登录到远程主机。
- gzip filename:将文件压缩为.gz文件。
- tar -zcvf file.tgz.:从当前目录创建压缩tar文件。
- tar -zxvf file.tgz.:从.tgz文件中解压文件。
- man:显示在线手册页。
- zip file.zip filenames:将文件压缩为.zip文件。
- unzip file.zip:解压.zip文件。
第二章 编程背景
让我最有收获的内容:
2.1 Linux中的文本编辑器
2.1.1 Vim
vim(Linux Vi和Vim Editor 2017)是Linux的标准内置编辑器。它是Unix原始默认vi编辑器的改进版本。与其他大多数编辑器不同,vim有3种不同的操作模式,分别是
- 命令模式:用于输入命令
- 插入模式:用于输入和编辑文本。
- 末行模式:用于保存文件并退出。
vim启动时,处于默认的命令模式,在该模式下,大多数键表示特殊命令。移动光标的命令键示例如下:
- h:将光标向左移动一个字符
- l:将光标向右移动一个字符
- j:将光标向下移动一个字符
- k:将光标向上移动一个字符
在X-window中使用vim时,也可以通过箭头键来完成光标的移动。要输入文本进行编辑,用户必须输入i(插入)或a(追加)命令将vim切换到插入模式:
- i:切换到插入模式,插入文本。
- a:切换到插入模式,追加文本。
要退出插入模式,请按ESC键一次或多次。在命令模式下,输入“:”进入末行模式,将文本保存为文件或退出vim:
- :w:写入(保存)文件。
- :q:退出vim。
- :wq:保存并退出。
- :q!:不保存更改,强制退出。
虽然许多Unix用户已经习惯了vim不同的操作模式,但是其他用户可能认为与其他基于图形用户界面(GUI)的编辑器相比,vim使用起来既不自然也不方便。以下类型的编辑器属于通常所说的所见即所得(WYSIWYG)编辑器。在WYSIWYG编辑器中,用户可以输入文本,用箭头键移动光标,和普通的文本输入一样。通常,通过输入一个特殊的meta键,接着输入一个字母键即可创建命令。例如:
- Ctrl+C:中止或退出。
- Ctrl+K:删除行到缓冲区。
- Ctrl+Y:从缓冲区内容中复制或粘贴。
- Ctrl+S:保存已编辑文本等。
2.3 程序开发
2.3.1 程序开发步骤
(1)创建源文件;
全局变量、局部变量、静态变量、自动变量和寄存器变量。
(2)用gcc把源文件转换成二进制可执行文件。
gcc t1.c t2.c
(3)gcc的步骤:
1.将C源文件转换为汇编代码文件,即将.c文件转为.s文件。
2.将汇编代码转换为目标代码,即将.s文件转为.o文件。
每个.o文件包含:
- 一个文件头
- 一个代码段
- 一个数据段
- 一个BSS段
- 指针、数据和重定位信息
- 符号表
3.链接。
- 将.o文件的所有代码段组合成单一代码段。
- 将所有数据段组合成单一数据段。
- 将所有BSS段组合成单一bss段。
- 使用.o文件的重定位信息调整组合指针、数据和bss段的偏移量。
- 用符号表来解析各个.o文件之间的交叉引用。
2.3.2 静态与动态链接
这是创建二进制可执行文件的两种方式。
静态库的特点:
链接器将所有必要的库函数代码和数据纳入a.out文件中。这使得a.out文件完整、独立,但通常非常大。
动态链接的优点:
- 减小每个a.out文件大小;
- 许多执行程序共享相同库函数;
- 修改库函数无需重新编译源文件。
动态链接所用的库称为动态链接库(DLL)。它们在Linux中称为共享库(.so文件)。动态加载(DL)库是指按需加载的共享库,可用作插件和动态加载模块。
2.3.3 可执行文件格式
1.二进制可执行平面文件
2.a.out可执行文件
3.ELF可执行文件
2.3.4 a.out文件的内容
1.文件头
2.代码段
3.数据段
4.符号表
2.3.5 程序执行过程
1.读取a.out文件头,以确定所需总内存大小;
2.sh从总大小中分配一个内存区给执行映像;
3.接着,sh放弃旧映像,开始执行新映像
4.执行从crt0.o开始,调用main()
2.3.6 程序终止
1.正常终止
2.异常终止
2.4 C语言中的函数调用
2.4.1 32位GCC中运行时堆栈使用情况
1.进程执行映像
2.每个CPU都有以下寄存器或同等寄存器:
- PC(IP):指向CPU要执行的下一条指令。
- SP(SP):指向栈顶。
- FP(BP):指向当前激活函数的栈帧。
- 返回值寄存器(AX):函数返回值的寄存器。
3.main函数由crt0.o调用。
4.每个函数入口,编译后的代码完成如下功能:
- 将FP压栈,在堆栈上保存CPU的FP寄存器。
- 让FP指向保存的FP#建立栈帧。
- 向下移动SP为堆栈上的自动局部变量分配空间。
- 编译后的代码可能继续向下移动SP,在堆栈上分配一些临时工作空间,用temps表示。
2.6 链接库
2.6.1 创建静态链接库
gcc -c mysum.c
ar rcs libmylib.a mysum.o
gcc -static t.c -L. -lmylib
a.out
2.6.2 创建动态链接库
gcc -c -fPIC mysum.c
gcc -shared -o libmylib.so mysum.o
gcc t.c -L. -lmylib
export LD_LIBRARY_PATH=./
a.out
标签:文件,二章,用户,映像,Unix,内核,Linux
From: https://www.cnblogs.com/qwer6653/p/16656357.html