1. 引言
1.1 Unix & Linux 简介及历史版本
Unix 和 Linux 是一系列强大的操作系统,具有丰富的历史和版本。Unix 的初始版本由肯·汤普森(Ken Thompson)和丹尼斯·里奇(Dennis Ritchie)于 20 世纪 70 年代早期开发。它是一种通用操作系统,经典书目包括 1988 年的《The C Programming Language》。
1.1.1 AT&T Unix
AT&T Unix 是 Unix 的一个重要分支,为 Unix 的发展做出了重要贡献。
1.1.2 Berkeley Unix
Berkeley Unix 也对 Unix 有着深远的影响,其创新包括网络套接字和众多的系统工具。
1.2 Linux 简介
Linux 是一个类 Unix 的操作系统,最初由 Linus Torvalds 在 1991 年为基于 Intel x86 的个人计算机开发的一个实验性内核。Linux 的发展得益于与 GNU 软件的结合,包括 GCC 编译器、GNU Emacs 编辑器和 Bash 等。
1.2.1 Linux 内核开发
Linux 内核的开发由 Linux 内核开发小组严格监督,所有 Linux 内核都完全相同,但在不同的发行版中可能有不同的软件包和用户界面。
1.3 Ubuntu Linux 简介
Ubuntu Linux 是基于 Debian 的 Linux 发行版,它注重易用性和用户友好性。用户在安装 Ubuntu 时需要创建一个用户名和密码,Ubuntu 会自动登录默认用户。为了执行特权操作,用户可以使用 sudo 命令。
1.3.1 强化学生的编程背景知识
本书的第一个目标是为学生提供高级编程所需的背景知识和技能,包括程序开发步骤、动态数据结构、进程管理、并发编程、定时器和定时功能、信号、信号处理和进程间通信、文件系统、TCP/IP 和网络编程等内容。
1.3.2 动态数据结构的作用
本书详细介绍了动态数据结构在实践中的用途和使用方式,强调了其重要性。
1.3.3 进程概念和进程管理
系统编程的重点是各种进程的抽象概念,包括系统启动、初始化进程、守护进程、登录进程等。
1.3.4 并发编程
并发编程是计算的未来,本书介绍了并发编程的基本概念和技术。
1.3.5 定时器和定时功能
定时器和定时功能在操作系统中起着重要作用,本书详细介绍了它们的应用和原理。
1.3.6 信号、信号处理和进程间通信
信号和信号处理是理解程序异常和进程间通信的关键,本书深入讨论了这些主题。
1.3.7 文件系统
除进程管理之外,文件系统是操作系统的重要组成部分,本书探讨了文件系统的结构和操作。
1.3.8 TCP/IP 和网络编程
网络编程是操作系统的另一大组成部分,本书介绍了 TCP/IP 协议、套接字 API、UDP 和 TCP 套接字编程,以及服务器-客户机模型。
1.4 Linux 文件系统
Unix/Linux 文件系统采用树形组织结构,包括目录文件、非目录文件(常规文件和特殊文件)、符号链接文件等。
1.4.1 文件路径名
Unix/Linux 文件系统树的根节点为根目录,路径名可以是绝对路径名(以 / 开头)或相对路径名。用户可以使用一系列常用命令来操作文件系统。
1.5 Linux 手册页
Linux 手册页保存在 /usr/man 目录中,分为不同类别。man 命令用于查看手册页。
1.6 用户账户和 sudo
Linux 用户账户信息保存在 /etc/passwd 文件中,用户可以使用 sudo 命令提升权限。新用户可以使用 adduser 命令添加。
1.7 Linux 命令
Linux 中有许多常用的命令,用于执行各种任务,包括文件和目录操作、系统管理和网络操作等。
1.7.1 常用命令示例
ls: 列出目录内容
cd: 更改目录
pwd: 打印当前工作目录
touch: 更改文件时间戳或创建文件
cat: 显示文件内容
cp: 复制文件
mv: 移动或重命名文件
mkdir: 创建目录
rmdir: 移除空目录
rm: 移除或删除文件
ln: 创建链接文件
find: 搜索文件
grep: 在文件中搜索模式
ssh: 远程登录
gzip: 压缩文件
tar: 打包和解压文件
man: 显示在线手册页
1.8 Linux 运行级别
Linux 内核以单用户模式启动,可以模仿 System V Unix 的运行级别,实现多用户模式运行。登录后,各登录进程等待用户登录。
1.8.1 登录进程
登录进程会为用户分配伪终端并等待用户登录。在使用 X Window 作为用户界面的 Linux 系统上,X Window 服务器通常充当用户登录界面。
1.8.2 命令执行
用户登录后,通常会执行命令解释程序 sh,该程序可解释并执行用户输入的命令,执行常见的文件和目录操作。
1.9 添加新用户和 sudo 命令
可以使用 adduser 命令来添加新用户。sudo 命令允许用户以超级用户特权执行命令,但需要配置 /etc/sudoers 文件以授权用户。2. 系统编程概述
系统编程是计算机科学领域中的一个重要分支,它涉及开发和维护操作系统、系统软件和应用程序,以及直接与计算机硬件交互的任务。这一章将深入探讨系统编程的各个方面。
第二章 编程背景
2.1、Linux中的文本编辑器
2.1.1 Vim
vim是Linux的标准内置编辑器。
vim有三种不同的操作模式,分别是命令模式、插入模式和末行模式。
命令模式:vim启动时,处于默认的命令模式。大多数键表示特殊命令。如操纵光标的上下左右分别为kjhl。
插入模式:当要输入文本进行编辑,必须输入i或a命令将vim切换到插入模式。其中i为插入文本,a命令为追加文本。要退出插入模式,按ESC键一次或多次即可。
末行模式:在命令模式下,输入“:”进入末行模式,将文本文件保存为文件或退出vim,具体有以下四个命令:
:w:写入(保存)文件
:q:退出vim
:wq:保存并退出
:q!:不保存更改,强制退出
2.1.2 gedit&emacs
Gedit是GNOME桌面环境默认的文本编辑器。
Emacs则可在多个不同的平台下运行。
两者都属于所见即所得(WYSIWYG)编辑器,相对vim,不需要模式切换。
2.2 程序开发
2.2.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.2.2 静态与动态链接
这是创建二进制可执行文件的两种方式。
静态库的特点:
链接器将所有必要的库函数代码和数据纳入a.out文件中。这使得a.out文件完整、独立,但通常非常大。
动态链接的优点:
减小每个a.out文件大小;
许多执行程序共享相同库函数;
修改库函数无需重新编译源文件。
动态链接所用的库称为动态链接库(DLL)。它们在Linux中称为共享库(.so文件)。动态加载(DL)库是指按需加载的共享库,可用作插件和动态加载模块。
2.2.3 可执行文件格式
1.二进制可执行平面文件
2.a.out可执行文件
3.ELF可执行文件
2.2.4 a.out文件的内容
1.文件头
2.代码段
3.数据段
4.符号表
2.2.5 程序执行过程
1.读取a.out文件头,以确定所需总内存大小;
2.sh从总大小中分配一个内存区给执行映像;
3.接着,sh放弃旧映像,开始执行新映像
4.执行从crt0.o开始,调用main()
2.2.6 程序终止
1.正常终止
2.异常终止
2.3 C语言中的函数调用
2.3.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表示。