当前位置:首页 >> 初中教育 >>

Linux系统分析基础


《操作系统原理与实践》 第1讲 Linux系统分析基础

叶保留
yebl@nju.edu.cn

南京大学计算机科学与技术系

教学目标
?了解Linux发展概况 ?了解Linux内核结构及编译方法 ?掌握Linux基本编程方法 ?掌握GNU编程工具 ?理解Linux程序执行机制

/>2

主要内容
?Linux简介 ?Linux内核环境 ?Linux编程环境 ?GNU make管理项目 ?Linux的程序执行机制

3

初识Linux
?类Unix(Unix-like)操作系统
?

其他类UNIX系统包括Solaris、Mac OS等

?基于GPL(GNU Public License)的自由操作系统
?

第一个版本发行于1991年

?主要用C语言编写,部分代码用汇编语言编写 ?―Linux‖在不同语境下的内涵不同
?
?

简 介

Linux
4

Linux内核、Linux系统、Linux开发套件等 严格来说,Linux指由Linux Torvalds维护(及通过主要 镜像网站发布)的内核

Linux发展史
?1991年11月,芬兰赫尔辛基大学的 Linus Torvalds
? ? ? ?

编写了一个小程序(取名为Linux),发布在互联网上 希望借此实现一个操作系统“内核” 一批高水平网络黑客参与,诞生Linux 1.0 版 Linux 的第一个商业版 Slackware 问世

?1993年
Linux
5

?1994年

简 介 ?1996年 ? 美国国家标准技术局计算机系统实验室确认 Linux 版本 1.2.13符合 POSIX 标准

?2001年
? ?

Linux2.4版内核发布 Linux2.6版内核发布

?2003年

Linux操作系统特征
?符合POSIX标准规范的操作系统
? ?

Portable Operation System Interface of Unix:可移植的 操作系统接口 由IEEE开发,ANSI和ISO标准化 抢占式多任务处理,支持多用户 图形用户接口 异构硬件支持 支持SMP 支持TCP/IP 多体系结构支持,支持32/64位CPU NFS、VFS、高效的EXT系列文件系统等

?具备现代操作系统的基本功能
? ? ? ? ? ?

简 介

Linux
6

?拥有其他操作系统没有的特色
?

Linux精髓
?代表一种开源文化
? ?

?

免费软件,开放源代码 自由软件,可在原有程序基础上开发自己的程序 GNU/Linux ? Linux仅指Linux内核 ? Linux系统的大部分应用都建立在GNU软件之上

简 ?核心结构 介 ? Linux内核 ? Linux Shell ? Linux文件系统 ? Linux应用系统 ? GNU Tools
7

Linux

Linux的系统结构
(the users) Shells and commands Compilers and interpreters System libraries System-call interface to the kernel Signals terminal File system swapping handling block I/O system character I/O system disk and tape driver terminal drivers CPU scheduling page replacement demand paging virtual memory

用户应用程序

用户态
Shell,库函数
系统调用 内核实现

简 介

Linux
8

核心态

Kernel interface to the hardware Terminal controllers terminals Device controllers disks and tapes Memory controllers physical memory

硬件资源管理接口

划分用户态/内核态的必要性
?不区分的缺陷
? ?

?
?

用户直接修改操作系统的数据 用户直接调用操作系统的内部函数 用户直接操作外设 用户任意读/写物理内存

简 介

Linux
9

?区分的意义
?

?

禁止用户程序和底层硬件直接打交道 ? 如果用户程序往硬件控制寄存器写入不恰当的值,可 能导致硬件无法正常工作 禁止用户程序访问任意物理内存,否则可能会破坏其他 程序的正常执行 ? 如果对核心内核所在的地址空间写入数据,会导致系 统崩溃

CPU对用户态/和心态划分的支持
?现代CPU都有几种不同指令执行级别
? ?

在高执行级别下,代码可以执行特权指令,访问任意的 物理地址,这种CPU执行级别就对应着内核态 在相应低级别执行状态下,代码的掌控范围会受到限制, 只能在对应级别允许的范围内活动 intel x86 CPU有四种不同的执行级别0-3 Linux只使用0级和3级分别表示内核态和用户态

简 介

Linux
10

?举例
? ?

用户态/和心态的区分方法
?cs寄存器最低两位表明当前代码的特权级
?

?

CPU每条指令的读取都是通过cs:eip这两个寄存器 ? cs:代码段选择寄存器 ? eip:偏移量寄存器 上述判断由硬件完成

简 介

Linux
11

?在Linux中,地址空间是一个显著的标志
? ?

0xc0000000以上地址空间:只能在内核态下访问 0x00000000 ~ 0xbfffffff的地址空间:两种状态下都可访 问 ? 注意,这里的地址空间是逻辑地址而不是物理地址

Linux的内核特点
?Linux是单内核、多模块系统
? ? ? ?

简 介

Linux内核运行在单独的内核地址空间 所有操作系统功能作为一个模块实现在其内核中 ? 模块均运行在内核态,直接调用函数,无需消息传递 具备模块化设计、抢占式内核(Linux 2.6支持,Linux 2.4 用户级抢占)、支持内核线程及动态装载内核模块的能力 与Unix主要区别 ? Linux汲取了微内核设计思想(基于模块定制内核)

Linux
12

?Unix也是单内核系统 ?Windows NT和Mach是微内核系统
? ?

只提供基础功能,其他功能通过服务实现 微内核功能被划分为多个独立过程,每个过程称为服务 器

Linux单内核结构
应用程序 用户态 标准函数库

简 介

Linux
13

系统调用(POSIX标准)接口

单内核

模块

模块 接口

设备 驱动

驱动 接口

内核 (进程管理、存储 管理、文件管理、 设备管理、网络 管理)

核心态

计算机硬件

Linux的内核版本
?Linux内核版本指由Linux开发小组(Linus Torvalds总协调)开发出系统内核的版本号 ?Linux内核采用双树系统
?
?

一棵是稳定树,主要用于发行 另一棵是非稳定树(开发树),用于产品开发和改进

简 介
第1位数字r 为主版本号

Linux
14

?Linux内核版本号由3位数字组成
r.x.y
第3位数字y为修改号, 表示错误修补的次数 第2位数字x为说明版本类型的次版 本号: 偶数表示产品化版本 奇数表示实验版本

主流的Linux发行版本

简 介

Linux
15

Linux与Windows的区别
?文件系统
? ?

Linux需要一个挂载根目录/的ext分区和一个作为虚拟内 存的swap分区 Linux没有盘符,可通过设备名挂载,挂在信息在 /dev/fstab,如 ? mount -t ntfs /dev/sda1 /mnt/win_c

简 ?Linux将所有设备都映射成/dev目录下的一个文件 介 ?用户管理 ? 系统管理员是root,使用su命令切换

Linux
16

主要内容
?Linux简介 ?Linux内核环境 ?Linux编程环境 ?Linux的系统初始化 ?Linux的程序执行机制

17

Linux内核核心组成

内 核 环 境

Linux
18

? 进程调度程序:负责控制进程访问CPU ? 内核管理程序:支持虚拟内存及多进程安全共享主存系统 ? 虚拟文件系统:抽象异构硬件设备细节,提供公共文件接口 ? 网络接口:提供对多种组网标准和网络硬件的访问 ? 进程间通信:为进程之间的通信提供实现机制

Linux内核源码的获取
?下载位置
? ?

www.kernel.org 以GNU zip和bzip2形式发布

?安装位置
内 核 环 境 Linux
19

? ?

?
?

一般安装在/usr/src/linux,不要将该源码树用于开发 在编译自己编写的C库所用的内核版本要链接到该树 不要以root身份对内核进行修改,应先建立自己的主目录, 仅以root身份安装新内核 安装新内核应该保持/usr/src/linux原封不动

Linux核心源码结构

内 核 环 境

Linux
20

Linux核心源码的组织
?arch 目录
?
?

包含与体系结构相关的核心代码,相关.h文件则放在 include/asm下 支持的每种CPU均有相应子目录,包含boot、kernel、lib 和mm等子目录
存放大多数内核函数 主要文件包括sched.c、time.c、sys.c、itimer.c、fork.c、 signal.c、softirq.c、resource.c、dma.c、printk.c等 独立于体系结构的主存管理文件 ? 包括实现虚拟主存管理的源代码

内 核 环 境

Linux
21

?/kernel目录
? ?

?/mm子目录
?

Linux核心源码的组织(续)
?/fs目录
? ?

存放VFS和系统支持的各种文件系统源代码 每个子目录对应一个特定文件系统 存放重要的内核.h头文件 为各种CPU专设一个子目录 通用子目录include/linux、include/net

?/include目录
?

? 内 ? 核 环 ?/ipc目录 境 ? 存放处理进程间通信所需源代码

Linux
22

Linux核心源码的组织(续)
?/drivers目录
?

存放所有设备驱动程序源代码

?/net子目录
?

存放网络子系统,如各种网卡和网络规程驱动程序

? 存放安全子系统代码 内 核 ?/sound目录 环 ? 存放语音子系统代码 境

Linux
23

?/security目录

Linux核心源码的组织(续)
?/init目录
? ?

存放内核引导和初始化代码 许多重要文件,如main.c、version.c就位于该目录下 存放内核需要的通用工具性内核函数(如对出错信息的 处理),它能够在引导时解压内核并装入主存

?/lib目录
?

内 核 ?/scripts目录 环 ? 存放编译内核所用脚本和用于系统配置的命令文件 境

Linux
24

?/documentation目录
?

存放内核源代码文档

Linux内核的配置组成
?采用模块化的内核配置系统 ?内核模块(Loadable Kernel Module)的概念
?

?

内 核 环 境

?

模块实际上是一种目标对象文件,没有链接,不能独立 运行 但是其代码可以在系统运行时链接到系统中作为内核的 一部分运行,或从内核中取下,从而可以动态扩充内核 的功能(不需要重新编译内核) 这种目标代码通常由一组函数和数据结构组成

Linux
25

内核模块的优点
?使得内核更加紧凑和灵活,可扩展 ?修改模块时,不必全部重新编译整个内核
?

系统如果需要使用新模块,只要编译相应的模块,然后 将模块插入即可

?模块可以不依赖于某个固定的硬件平台 内 ?模块的目标代码一旦被链接到内核,它的作用域和 核 静态链接的内核目标代码完全等价
环 境

Linux
26

内核模块的使用
?并不是所有地方都使用内核模块
? ?

?

内 核 环 境

设备驱动程序 文件系统驱动程序 系统调用 ? 大部分系统调用属于基础内核(Basic kernel),也可 以以内核模块方式增加新的系统调用或者覆盖现有基 于内核模块方式实现的系统调用

Linux
27

模块示例
?程序代码:helloworld.c
#define MODULE #include <linux/module.h> int init_module(void) { printk(―<1>Hello World!\n‖); return 0; } void cleanup_module(void) { printk(―<1> Goodbye!\n‖); }

内 核 环 境
? ? ?
28

Linux

?编译、安装方法
root# gcc -c helloworld.c root# insmod helloworld.o root# lsmod root# rmmod helloworld

?

内核模块与应用程序的差别
C语言程序
运行 用户空间 main() 无 gcc -c gcc 直接运行 gdb

模块
内核空间 init_module() cleanup_module()

内 核 环 境

Linux
29

入口 出口 编译 连接 运行 调试

gcc -c -D_KERNEL_-DMODULE insmod insmod kdbug, kdb, kgdb等

Linux内核编译时的模块选配参数
?控制需要编译到内核的二进制映象(启动时载入) 和在需要时才装入的内核模块
?

?

内 核 环 境

配置选项命名形式:CONFIG_FEATURE ? 如CONFIG_SMP表示支持对称多处理器 配置项选择模式 ? 二选一:yes或no ? 三选一:yes、no或module
? Yes选项表示把代码编译进主内核映象,而不作为模块 ? Module意味该配置项被选定,但编译时该功能的实现代码是以

Linux
30

模块形式生成 ? 驱动程序一般都用三选一形式
? 字符串或整数 ? 不控制编译过程,只是指定内核源码可以访问的值,如定义 静态变量 ? 一般以预处理宏的形式表示

Linux内核编译的基本架构
?内核编译主要工具文件
文件类型
Makefile .config

作用
顶层Makefile文件 内核配置文件

arch/$(ARCH)/Makefile
scripts/Makefile.* kbuild Makefiles

机器体系Makefile文件
所有内核Makefiles共用规则 其它Makefile文件

?内核编译后,会在/boot目录生产以下文件
? ? ?
31

vmlinuz文件 initrd.img文件 System.map文件

Linux内核配置系统组成
?Makefile
?

定义编译链接规则、位于linux源代码各目录

?配置文件(config.in或kconfig)
?
? ? ? ? ?

提供内核的配置选择和设置
文本命令行工具:make config 基于ncurse的图形工具:make menuconfig 基于X11的图形工具:make xconfig 基于gtk+的图形工具:make gconfig 创建默认配置:make defconfig 配置工具输出文件 ? .config文件:用#include包括到主Makefile中 ? include/linux/autoconf.h:用#include包括到各个.c文件
? 每个.c文件都有<#include/linux/autoconf.h>代码项

内 核 环 境

Linux
32

?配置工具

?

主Makefile功能
?采用GNU编译工具对.config中的源文件列表编译
?

?

内 核 环 境

完成内核文件的配置、依赖关系及模块的生成,随后调 用Rules.make编译文件 ? Rules.make定义所有Makefile共用的编译规则 Makefile支持的make命令 ? make mrproper:检查.o文件及文件依赖关系的正确性 ? make config:配置内核并生成配置文件 ? make dep:根据配置文件创建相应的依赖关系树 ? make clean:清除旧版本的目标文件 ? make zImage:编译并用gzip压缩成1MB以下的内核
? 未压缩的文件是vmlinuz

Linux
33

? make

bzImage:编译并用gzip压缩成1MB以上的内核 ? make modules:编译模块 ? make modules_install :安装模块 ? depmod –a:生成模块之间的依赖关系

Linux内核的编译、安装过程
?准备阶段
? ?

内 核 环 境

?

下载源码:www.kernel.org 将源码解压到/usr/src目录下 ? tar xvjf linux-x.y.z.tar.bz2 ? tar xvzf linux-x.y.z.tar.gz ? 解压位置:linux-x.y.z目录下 建立内核编译环境 ? ln –sf linux-x.y.z linux ? cd /usr/include ? rm -rf asm linux scsi ? ln -sf /usr/src/linux/include/asm-i386 asm ? ln -sf /usr/src/linux/include/linux linux ? ln -sf /usr/src/linux/include/scsi scsi

Linux
34

Linux内核的编译、安装过程(续)
?配置内核
? ? ?

? ?

? 内 核 环 ?编译、安装内核 境 ? 编译内核:make ? 编译模块:make modules ? 安装模块:make modules_install ? 生成模块依赖关系:depmod –a ? 安装内核:make install
35

检查文件依赖关系正确性:make mrproper 获取默认.config文件:cp /boot/config-`uname -r` .config 生成配置文件:make config 创建依赖关系树:make dep 清除旧版本目标文件:make clean 生成压缩形式内核文件:make bzImage或make zImage ? 编译后的文件在/usr/src/linux/arch/i386/boot目录下

Linux

Linux内核的编译、安装过程(续)
?配置启动文件
?

内 核 环 境
?

将内核映像拷贝到合适位置,并按启动要求启动 ? #cp /usr/src/linux/arch/i386/boot/zImage /boot/zImagex.y.z ? #cp /usr/src/linux/System.map /boot/System.map-x.y.z ? ln –sf /boot/vmlinuz-x.y.z /boot/vmlinuz ? ln –sf /boot/System.map-x.y.z /boot/system.map
? 系统正常启动时不会读这个符号表;主要是为了内核引导出

Linux
36

错时便于调试

/boot/initrd-x.y.z.img x.y.z 如果是LILO启动方式,编辑/etc/lilo.conf

? /sbin/mkinitrd

Linux内核的编译、安装过程(续)
?lilo.conf修改方法
image=/boot/vmlinux-2.4.7-10 label=linux read-only root=/dev/hdal image=/boot/zImage-x.y.z // 新内核 label=newkernel read-only root=/dev/hdal
? 注意:必须运行lilo命令将激活新配置。如果是grub,

// 旧内核

则不需要。
37

Linux系统的文件系统结构

内 核 ? /:文件系统结构的起始点 环 ? /home:用户主目录 境 ? /bin:标准指令和工具程序
? ? ? ?
38

Linux

/usr :系统使用文件和指令 /usr/bin:用户命令和工具程序 /usr/sbin:系统管理员命令 /usr/lib:编程语言库

? ? ? ? ? ? ?

/usr/doc:Linux文档 /usr/man:在线联机帮助手册 /usr/spool:假脱机文件 /sbin:管理员开启系统的命令 /var:时变文件,例如邮箱文件 /dev:设备文件接口 /etc:系统配置文件及其它系统文件

主要内容
?Linux简介 ?Linux内核环境 ?Linux编程环境 ?GNU make管理项目 ?Linux的程序执行机制

39

Linux系统的用户视图
用户 用户 用户
Shell 核外程序 高级语言和实用程序

用户

编 程 环 境

Linux
40

系统调用
文件子系统 内核 高速缓存 字符设备 块设备 设备驱动程序 进程间通信 调度程序 存储管理

进程 管理 子系统

硬 件 控 制
硬 件

C程序员的系统视图

编 程 环 境

Linux
41

系统调用与函数库
?系统调用
? ?

Linux内核的对外接口 用户程序和内核之间唯一的接口 依赖于系统调用 标准函数库建立在系统调用的上层,提供的功能比系统 调用强,使用也比较方便 ? 静态库(.a文件) ? 动态库/共享库 (.so文件)

?函数库
? ?

编 程 环 境

Linux
42

Linux支持的编程语言
?高级编程语言
? ?

编 程 ?脚本 环 ? Shell: sh/bash, csh, ksh 境 ? Perl, Python, tcl/tk, sed, awk…

C/C++, Java, Fortran… ELF二进制格式 ? Executable and Linkable Format ? 工具接口标准委员会(TIS)选择ELF体系作为不同操作 系统之间可移植的二进制文件格式

Linux
43

文件名后缀
.c .i .cc .cp .cpp .CPP. c++ .C .cxx .ii .h .H .hh .s .S .o .a .so 必须被预处理的C源代码 无需预处理的C源代码 必须被预处理的C++源代码 无需预处理的C++源代码 必须转换成预编译头文件的C /C++头文件 必须转换成预编译头文件的C++头文件 汇编代码 必须被预处理的汇编代码 目标文件 静态库文件(归档文件) 动态库文件(动态对象)

编 程 环 境

Linux
44

集成环境
?集成开发环境IDE
? ?

?

Emacs/xemacs Kdevelop Eclipse 编辑器 ? vi/vim/gvim, emacs/xemacs, pico 代码阅读器 ? source navigator,vi/emacs+ ctags/etags

编 程 环 境

Linux
45

?命令行开发环境
?

?

?

配置工具 ? automake, autoconf, …

GNU开发工具
?GCC
?

GNU C编译器

?Binutils
?
?

辅助GCC的主要软件
GNU调试工具 gdb调试命令

编 ? 程 环 ?二进制代码工具 ? as, ld, ar, ldd… 境

Linux
46

?GDB

?Make ?CVS
?

版本控制

GCC
?GCC不只是一个C编译器
?

GCC = GNU Compiler Collection

?GCC支持多种高级语言的编译
?
? ? ? ? ?

编 程 环 境

C、C++ ADA Object C JAVA Fortran PASCAL

Linux
47

GCC工具
?cpp
? ?

预处理器 GNU C编译器在编译前自动使用cpp对程序进行预处理 符合ISO等标准的C编译器

?gcc
?

编 ?g++ 程 ? 基本符合ISO标准的C++编译器 环 境 ?gcj ? GCC的java前端

Linux
48

?gnat
?

GCC的GNU ADA 95前端

GNU工具—gcc
?是一个强大的工具集合,包含预处理器、编译器、 汇编器、链接器等组件
?

?

由输入文件类型和传递的参数决定gcc具体调用的组件 为开发者提供足够多的参数,可让开发者全面控制代码 的生成

编 ?gcc下的C程序编译过程 ? 预处理 程 环 ? 编译成汇编代码 境 ? 汇编成目标代码 ? 链接

Linux
49

gcc使用举例
?源程序

编 程 环 境

Linux
50

gcc使用举例
?编译和运行
? ?

参数-o:指定目标名称(缺省gcc编译出来的文件是a.out) 参数-ansi:关闭GNU C中与ANSI C不兼容特性,激活 ANSI C专有特性 ? 包括禁止一些asm inline typeof关键字,以及UNIX,vax 等预处理宏

编 程 环 境
运行

Linux
51

编译

gcc的工作过程
?使用-v选项,可看到许多被隐藏的信息

编 程 环 境

Linux
52

预处理
?使用-E参数激活预处理,输出文件的后缀为“.cpp‖
gcc –E –o gcctest.cpp gcctest.c

?使用wc命令比较预处理后的文件与源文件,可以看 到两个文件的差异

编 程 环 境

Linux
53

wc命令示例
预编译

行数 单词数 字节数

编 程 环 境

Linux
54

编译成汇编代码
?预处理文件?汇编代码
?

?

使用-x参数说明根据指定的步骤进行工作 ? cpp-output指明从预处理得到的文件开始编译 使用-S说明生成汇编代码后停止工作 gcc –x cpp-output –S –o gcctest.s gcctest.cpp

编 ?也可以直接编译到汇编代码 gcc –S gcctest.c 程 环 境

Linux
55

编译成汇编代码

预处理文件?汇编代码

编 程 环 境
直接编译到汇编代码

Linux
56

编译成目标代码
?汇编代码?目标代码
?

gcc –x assembler –c gcctest.s ? --c:只编译不链接

编 程 环 境

Linux
57

汇编代码?目标代码

编译成目标代码
?直接编译成目标代码
?

gcc –c gcctest.c

编 程 ?使用汇编器生成目标代码 ? as –o gcctest.o gcctest.s 环 境
使用汇编器

Linux
58

直接编译成目标代码

编译成执行代码
?目标代码?执行代码
?

gcc –o gcctest gcctest.o

编 程 ?直接生成执行代码 环 ? gcc –o gcctest gcctest.c 境

Linux
59

gcc的高级选项
?-Wall:打开所有的警告信息

编 程 环 境

Linux
60

根据警告信息检查源程序

编 程 环 境

Linux
61

main函数的返回值为int

在函数的末尾应当返回一个值

修改源程序

编 程 环 境

Linux
62

gcc优化编译
?优化编译选项
? ?

编 程 环 境

?

?

63

-O0:缺省情况,不优化 -O1:第一级优化 ? 优化取决于目标处理器 ? 通常包括线程跳转(减少跳转次数)、延迟退栈(在 嵌套函数调用时推迟退栈时间,直到递归结束) -O2: ? 包括O1级优化 ? 调整处理器指令执行时序,优化处理器在等待其他指 令结果或数据延迟时可执行其他不相关指令 -O3 ? 包括O2级优化 ? 使内嵌函数、循环展开 ? 执行与特定处理器特性相关的优化

Linux

gcc优化编译举例

编 程 环 境

Linux
64

不同的优化 编译选项

gcc优化编译举例(续)
?使用time命令统计程序的运行

编 程 环 境

Linux
65

66

GNU binutils简介
?是一组二进制工具程序集
?

?

编 程 环 境

?

?
67

addr2line ? 将程序地址转换为文件名和行号 ? 在命令行中给出地址和可执行文件名,使用可执行文 件的调试信息指出对应源文件以及行号 ar ? 建立、修改、提取归档文件 ? 归档文件结构保证可恢复原始文件内容 as ? GNU汇编器,主要用来编译gcc输出的汇编文件 ? 将汇编代码转换成目标代码,并放到一个文件 ? 该目标文件将由连接器ld连接 ld ? 连接器,将目标和归档文件结合起来形成可执行文件 ? 通常,建立一个新编译程序的最后一步就是调用ld

Linux

GNU binutils简介(续)
?
? ?

编 程 环 境

?

? ?
68

nm ? 列出目标文件中的符号 objcopy ? 将一种类型目标文件转换成另一种类型的目标文件 objdump ? 显示一个或更多目标文件的信息 ? 使用选项来控制其显示的信息 ranlib ? 产生归档文件索引,并将其保存到这个归档文件中 ? 索引列出归档文件各成员所定义的可重分配目标文件 readelf ? 显示elf格式可执行文件的信息 size ? 列出目标文件每一段的大小以及总体的大小

Linux

ar
?用于建立、修改、提取归档文件(archive)
? ?

一个归档文件可包含多个文件(也可认为归档文件是一 个库文件) 归档文件保存被包含原始文件的内容、权限、时间戳、 所有者等属性,在提取后可被还原

编 程 环 境

Linux
69

使用ar建立库文件
?源程序add.c和minus.c

编 程 环 境

Linux
70

使用ar建立库文件(续)
编译成目标文件

ar的rv参数的说明: r:将多个文件组成一个文件 v:输出信息

编 程 环 境
将库文件拷贝到/usr/lib目录下

Linux
71

调用ar建立的库文件
?代码中使用Add和Minus函数

编 程 环 境

Linux
72

调用ar建立的库文件(续)
?在编译时指定库文件

编 程 环 境

Linux
73

指明将libtest.a链接进来 运行结果

nm
?列出目标文件中的符号
?

程序员可定位和分析执行程序/目标文件中的符号信息及 其属性 A:符号的值是绝对值,不会被将来的链接所改变 B:符号位于未初始化数据部分(BSS段) C:符号是公共的 ? 公共符号是未初始化的数据 ? 在链接时,多个公共符号可能以相同的名字出现 ? 如果符号在其他地方被定义,则该文件中的这个符号 会被当作引用来处理 D:符号位于已初始化的数据部分(data段) T:符号位于代码部分(text段) U:符号未被定义 ?:符号类型未知或目标文件格式特殊

?显示的符号类型
编 程 环 境 Linux
74

? ? ?

?
? ? ?

nm使用举例

编 程 环 境

Linux
75

objcopy
?将一种格式文件生成另一种格式文件
使用file命令查看文件类型

编 程 环 境

Linux
76

生成srec格式的目标文件

使用file命令查看新文件的类型

Linux的可执行文件格式
? a.out格式(assembler and link editor output)
? ? ?

早期UNIX系统使用的可执行文件格式 文件头部结构定义(include/asm-x86/a.out.h) 现在基本被ELF文件格式代替 包括文件头、可选头部及一些节(section) .text, .data和.bss区段各有一个小节,还可包含其他区段 一个可选头部,对不同操作系统作特定定义 文件定义位置:include/linux/coff.h 代码、链接和注释都以段存在,节点表(Section Header Table) 有一个表项与每个小节对应 文件类型:.o目标文件、.so动态库文件、可执行文件 ELF格式可以比COFF格式包含更多的调试信息 MOTOROLA S-Recoder格式(S记录格式文件)

? COFF格式(Common Object File Format)
? ?

编 ? 程 ? 环 境 ? ELF格式(Executable and Linking Format)
? ? ?
77

Linux

? SREC
?

objdump
?显示一个或多个目标文件的信息
? ?

?

由相应选项控制显示哪些信息 可通过该工具查看执行文件或库文件的信息 objdump对编写编译工具、分析代码执行机制非常有用

编 程 环 境

Linux
78

objdump使用举例
-f选项:显示文件头内容

编 程 环 境

Linux
79

objdump使用举例(续)
-d选项进行反汇编

编 程 环 境

Linux
80

readelf
?显示一个或多个ELF格式的目标文件信息

编 程 环 境

Linux
81

GNU gdb
?gdb = GNU debuger
? ?

?
? ? ?

编 程 环 境

设置断点 监视、修改变量 单步执行 显示/修改寄存器的值 查看堆栈 远程调试

Linux
82

gdb常用命令
file break/tbreak 打开要调试的文件 设置断点,可以是行号、函数名及地址(以*开 头) ;tbreak: 设置临时断点 执行当前调试的程序 列出源代码的一部分 执行一条语句但不进入函数内部 执行一条语句,是函数则进入函数内部 显示表达式的值 临时显示表达式的值 中止正在调试的程序 退出gdb 不退出gdb就执行shell命令 不退出gdb就执行make

编 程 环 境

Linux
83

run list next step display print kill quit shell make

gdb使用举例
?源代码如下
编译: gcc –o bug bug.c

编 程 环 境

Linux
84

gdb使用举例
?编译并运行

编译

编 程 环 境

Linux
85

????

使用gdb调试bug

编 程 环 境

Linux
86

运行bug

输入字符串hello 显示出错位置 能不能看到源代码呢?

使用gcc的-g参数
?gcc –g –o bug bug.c
?

-g:在可执行程序中包含标准调试信息

?重新调试
Linux
87

编 程 环 境

列出源代码

使用gcc的-g参数

设置断点

编 程 环 境
?怎么修改前面的源代码呢?

Linux
88

主要内容
?Linux简介 ?Linux内核环境 ?Linux编程环境 ?GNU make管理项目 ?Linux的程序执行机制

89

GNU make
?代码维护工具,使用GNU编译开发大型应用时常需 要使用make管理项目
?

?
?

管 理 项 目

避免重复使用多个复杂命令行维护项目和生成目标代码 make通过将命令行保存到Makefile中简化编译工作 make根据Makefile中定义的规则和步骤及各个模块的更 新情况,自动完成整个软件项目的维护和代码生成工作 ? make可识别Makefile中的被修改文件,并在再次编译 的时候只编译这些文件,从而提高编译的效率 ? make会检查文件的修改和生成时间戳
? 如果目标文件的修改或者生成时间戳比它的任意一个依赖文

Linux make
90

件旧,则make就执行makefile文件中描述的相应命令,以便更新 目的文件

GNU make特点
?适合于支持多文件构成的大中型软件项目的编译、 链接、清除中间文件等管理工作 ?提供和识别多种默认规则,方便对大型软件项目的 管理 ?支持对多目录的软件项目进行递归管理 ?对软件项目具有很好的可维护性和扩展性

管 理 项 目

Linux make
91

Makefile
?Makefile被make读取 ?Makefile主要工作
? ? ?

定义依赖关系 ? 生成目标文件所依赖的文件列表 需要用什么命令来产生目标文件的最新版本 定义编译、链接等相关参数

管 理 项 目

Linux make
92

Makefile的规则
? 规则内容
? ? ?

要创建的目标(文件) 创建目标(文件)所依赖的文件列表 通过依赖文件创建目标文件的命令组

管 理 项 目

Linux make
93

?规则一般形式
target ... : prerequisites ... <tab>command <tab>... <tab>... 依赖性 目标
main.o: main.c sum.h
操作命令 tab gcc –c main.c 规则

简单Makefile示例
edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.o cc -o edit main.o kbd.o command.o display.o insert.o \ search.o files.o utils.o main.o : main.c defs.h cc -c main.c kbd.o : kbd.c defs.h command.h cc -c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h buffer.h cc -c display.c insert.o : insert.c defs.h buffer.h cc -c insert.c search.o : search.c defs.h buffer.h cc -c search.c files.o : files.c defs.h buffer.h command.h cc -c files.c utils.o : utils.c defs.h cc -c utils.c clean : rm edit main.o kbd.o command.o display.o insert.o \ search.o files.o utils.o

管 理 项 目

Linux make
94

make的工作过程
?缺省情况下从Makefile中的第一个目标开始执行 ?执行过程类似一次深度优先遍历
Linux make
95

sum (exe) main.o sum.o

管 理 项 目

main.c

sum.h

sum.c

sum.h

sum: main.o sum.o gcc –o sum main.o sum.o main.o: main.c sum.h gcc –c main.c sum.o: sum.c sum.h gcc –c sum.c

默认依赖规则说明
?.o依赖于相应的.c文件
Linux make
96

管 理 项 目

sum: main.o sum.o sum: main.o sum.o gcc –o sum main.o sum.o gcc –o sum main.o sum.o main.o: main.c sum.h main.o: sum.h gcc –c main.c gcc –c main.c sum.o: sum.c sum.h sum.o: sum.h gcc –c sum.c gcc –c sum.c

Makefile中的变量
?变量功能
? ?

?
?

降低错误风险,简化Makefile 贮存一个文件名列表 贮存可执行文件名 贮存编译器标志参数
objects = main.o kbd.o command.o \ display.o insert.o search.o files.o utils.o edit: $(objects) cc -o edit $(objects)

管 理 项 目

Linux make
97

?变量使用示例:objects变量($(objects))

预定义变量
?make可直接使用许多预定义的变量
? ?

?
? ? ? ? ? ?

管 理 项 目

?

AR:归档维护程序的名称,默认值为 ar ARFLAGS:归档维护程序的选项 AS:汇编程序的名称,默认值为 as ASFLAGS:汇编程序的选项 CC:C 编译器的名称,默认值为 cc CFLAGS:C 编译器的选项 CXX:C++ 编译器的名称,默认值为 g++ CPPFLAGS:C 预编译的选项 …… 系统环境变量的处理 ? make 过程中被解释成make变量

Linux make
98

简化后Makefile文件
objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o
edit : $(objects) cc -o edit $(objects) main.o : defs.h kbd.o : defs.h command.h command.o : defs.h command.h display.o : defs.h buffer.h insert.o : defs.h buffer.h search.o : defs.h buffer.h files.o : defs.h buffer.h command.h utils.o : defs.h .PHONY : clean clean : rm edit $(objects)

管 理 项 目

Linux make
99

内部变量
? $@:目标文件的完整名称 ? $*:不包含扩展名的目标文件名称 ? $<:依赖列表中的第一个依赖文件 ? $+:所有的依赖文件
?

管 ? $%:若目标是归档成员,则该变量表示目标的归档成员名 ? 例如,如果目标名称为 mytarget.so(image.o) 理 ? $@ 为 mytarget.so 项 ? $% 为 image.o 目 ? 举例
CC = gcc CFLAGS = -Wall -O -g foo.o : foo.c foo.h bar.h $(CC) $(CFLAGS) -c $< -o $@
100

Linux make

以空格分开,并以出现的先后为序,可能包含重复的依赖文件

? $^:整个依赖列表(除去所有重复的文件名) ? $? :所有的依赖文件
?

以空格分开,这些依赖文件的修改日期比目标的创建日期晚

隐式规则 (Implicit Rules)
?也称预定义规则
?

告诉make在没有给出某些命令的时候如何处理
objects = main.o kbd.o command.o utils.o edit: $(objects) cc -o edit $(objects)

?举例

管 理 项 目

101

Linux make

?

问题:没有定义如何编译生成这些目标的规则 ? 对名为somefile.o的目标文件,make首先找与之对应的 源代码somefile.c,并用gcc –c somefile.c –o somefile.o 编译生成目标代码 ? 注意
? 若在工作目录下有对应的somefile.p文件,make会激活pascal

编译器工作
?

可使用预定义变量改变隐含规则的工作方式,如
?

$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@

102

模式规则
?扩展make隐式规则的方法
?

类似于普通规则,但目标必定含有符号% ? 该符号可与任何非空字符串匹配 ? 为与目标中的‖%‖匹配,该规则关联的相关文件部分 也必须使用‖%‖ %.o : %.c ? make从somefile.c文件为所有形为somefile.o的文件 somefile.o目标 make定义的模式规则 %.o : %.c $(CC) $(CFLAGS) $(CPPFLAGS) \ $(TARGET_ARCH) -c $< -o $@

管 理 项 目

103

Linux make

?举例
?

?

伪目标PHONY
?不对应于实际的文件,目标体规定make执行的命令
clean:
? ? ?

管 理 项 目

$rm *.o exec_file 由于目标体clean没有依赖体,make认为其是最新的而不 执行任何操作,因此它将永远不会被执行 若需执行,需显式执行命令 make clean 解决方法:. PHONY ? PHONY的依赖体文件的含义与通常一样 ? make不检查是否存在有文件名与依赖体中的一个名字 相匹配的文件,而直接执行与之相应的命令
.PHONY: clean clean:

104

Linux make

$rm *.o exec_file

伪目标PHONY(续)
?PHONY目标也可以有依赖关系
?

?

管 理 项 目

当一个目录中有多个程序,将其放在一个makefile 中会 更方便 因为缺省目标是makefile 中的第一个目标,通常将这个 phony 目标叫做"all",其依赖文件为各个程序 ? all : prog1 prog2 prog3 .PHONY: all prog1 : prog1.o utils.o cc -o prog1 prog1.o utils.o prog2 : prog2.o cc -o prog2 prog2.o prog3 : prog3.o sort.o utils.o cc -o prog3 prog3.o sort.o utils.o

105

Linux make

Makefile中的函数
?计算待操作的文件、目标或待执行的命令 ?使用方法
?

$(function arguments) $(subst from, to, text) :替换字符串 ? $(subst ee, EE, feet on the street) ? 相当于`fEEt on the strEEt` $(patsubst pattern, replacement, text) ? $(patsubst %.c,%.o, x.c.c bar.c) ? 相当于`x.c.o bar.o` $(wildcard pattern) :列出当前目录下所有符合模式 pattern格式的文件名 ? $(wildcard *.c) ? objects := $(wildcard *.o)

管 理 项 目

106

Linux make

?典型函数
?

?

?

Makefile中的条件语句
?四种条件语句
? ?

?
?

ifeq...else...endif ifneq…else…endif ifdef…else…endif ifndef...else…endif conditional-directive text-if-true endif 或 conditional-directive text-if-true else text-if-false endif

管 理 项 目

107

Linux make

带条件的makefile举例
sum: main.o sum.o gcc –o sum main.o sum.o main.o: main.c sum.h gcc –c main.c #deciding which file to compile to create sum.o ifeq ($(USE_SUM), 1) sum.o: sum1.c sum.h gcc –c sum1.c –o $@ else sum.o: sum2.c sum.h gcc –c sum2.c –o $@ endif

管 理 项 目

108

Linux make

可移植GNU 包的典型安装方法
?下载源代码包foo-1.0.tar.gz ?tar xvzf foo-1.0.tar.gz 问题1:配置脚configure 是如何生成的? ?cd foo-1.0 ?./configure 问题2:configure脚本怎么 ?make 知道该如何生成Makefile? ?(su) make install
幕后英雄:GNU Auto 工具 autoconf, automake, libtool, autoscan, autoheader……

管 理 项 目

109

Linux make

autoconf框架图

管 理 项 目

110

Linux make

autoscan Src code configure.scan

edit configure.in

aclocal aclocal.m4 autoconf configure

autoheader

automake
Makefile.am Makefile.in

./configure Makefile

autoconf流程 — autoscan
?为软件包创建configure. scan文件
?

? ?

从源文件中抽取与函数调用和头文件相关的信息,并为 相应包创建一个 configure.scan文件(configure.in前身) autoscan在以命令行参数中指定的目录为根(如果未给定 参数,则以当前目录为根)的目录树中检查源文件 基于perl语言实现
autoscan configure.scan edit configure.in aclocal autoconf configure aclocal.m4

管 理 项 目

111

Linux make

Src code

autoheader automake Makefile.am Makefile.in

./configure Makefile

autoconf流程 — autoscan(续)
?configure.scan示例
AC_PREREQ([2.64]) //表明文件所需要的autoscan版本 #AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS) AC_INIT([hello], [1.0], [user@gmail.com]) #侦测所指定源代码文件是否存在,来确定源代码目录的有效性 AC_CONFIG_SRCDIR([helloworld.c]) #用来生成config.h文件,以便autoheader使用 AC_CONFIG_HEADERS([config.h]) #指定编译器,如果不指定,选用默认gcc AC_PROG_CC # Checks for libraries. # Checks for header files. # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_OUTPUT(Makefile )

管 理 项 目

112

Linux make

autoconf流程 — edit
?编辑configure.scan,生成configure.in
? ?

?

管 理 项 目

?

由configure.scan文件更名而来 是configure脚本的输入文件 解决在不同unix变种之间移植程序的问题 ? 库名可能不同 ? 应用程序名可能不同 ? 结构和常量的定义可能不同…… configure脚本完成autoconf与automake的初始化工作 ? 为不同的平台定义相应的宏 ? 检测并指定适当的程序名、库名、结构和常量名等 ? 指定要为哪些目录输出Makefile文件

113

Linux make

autoconf流程 — edit
?confiugre.in文件的一般布局
? ? ? ? ? ?

管 理 项 目

?
? ? ?

AC_INIT 测试程序 测试函数库 测试头文件 测试类型定义 测试结构 测试编译器特性 测试库函数 测试系统调用 AC_OUTPUT

114

Linux make

autoconf流程 — edit(续)
宏定义
Linux make

含 义

检查lib库中是否存在指定的函数 AC_CHECK_LIB 1)测试成功时,执行shell命令action_if_found或者 (library, function, [action- action_if_found 2)当为空时,在输出变量LIBS中添加-llib if-found], [action-if-not3)action_if_not_found将-lother_libs选项传给link found], [other-libraries]) 命令

AC_INIT(FILE)

检查源代码所在路径

管 1)这个宏是必须的,描述将要生成的软件包的名 字及其版本号:PACKAGE是软件包的名字, 理 项 AM_INIT_AUTOMAKE( VERSION是版本号 2)当你使用make dist命令时,它会给你生成一个 目 PACKAGE, VERSION)
类似helloworld-1.0.tar.gz的软件发行包,其中就有对 应的软件包的名字和版本号 检查系统所用的C编译器 要输出的Makefile的名字

AC_PROG_CC AC_OUTPUT(FILE)
115

autoconf流程 — edit(续)
?configure.in示例
AC_PREREQ([2.64]) AC_INIT([hello], [1.0], [user@gmail.com]) AM_INIT_AUTOMAKE(hello, 1.0) AC_CONFIG_SRCDIR([helloworld.c]) AC_CONFIG_HEADERS([config.h]) # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_OUTPUT (Makefile)

管 理 项 目

116

Linux make

autoconf流程 — aclocal
?根据configure.in文件内容自动生成aclocal.m4文件
? ?

m4是传统Unix的宏处理的安装启动的应用,对应的 是.m4文件,记录了很多无法理解的宏 aclocal也是一个perl脚本程序

管 理 项 目

117

Linux make

Src code

autoscan

configure.scan

edit

configure.in

aclocal autoconf

aclocal.m4

autoheader automake Makefile.am Makefile.in

configure

./configure Makefile

autoconf流程 — automake
?automake要用的脚本配置文件是Makefile.am
?

Makefile.am 是一种比Makefile更高层次的规则 ? 指定要生成什么目标,它由什么源文件生成,要安装 到什么目录 ? 需要由开发人员自己创建 ? automake工具转换成Makefile.in(生成Makefile文件的 模板)
autoscan configure.scan edit configure.in aclocal autoconf configure aclocal.m4

管 理 项 目

118

Linux make

Src code

autoheader automake Makefile.am Makefile.in

./configure Makefile

autoconf流程 — automake(续)
?Makefile.am规则
? ?

头文件 ? include_HEADERS 数据文件 ? data_DATA 可执行文件 静态库 ? ? ? ? ? lib_LIBRARIES = libfoo.a foo_a_SOURCES = foo_a_LDADD = foo_a_LIBADD = foo_a_LDFLAGS =

管 理 项 目

119

Linux make

? ? ? ? ?

bin_PROGRAMS = foo foo_SOURCES = foo_LDADD = foo_LDFLAGS = foo_DEPENDENCIES =

autoconf流程 — automake(续)
?Makefile.am支持目标体使用的全局变量
?

管 理 项 目

? ? ? ? ?

bin_PROGRAMS或lib_LINRARIES:定义要产生的执行 文件名 ? 如果要产生多个执行文件,每个文件名用空格隔开 ? 对于可执行文件和静态库类型,如果只想编译,不想 安装到系统中,可以用 noinst_PROGRAMS代替 bin_PROGRAMS,noinst_LIBRARIES代替 lib_LIBRARIES INCLUDES:链接时所需要的头文件 LDADD:链接时所需要的库文件 LDFLAGS:链接时所需要的库文件选项标志 EXTRA_DIST:源程序和默认文件将自动打入.tar.gz包 SUBDIRS:在处理本目录之前要递归处理哪些子目录

120

Linux make

autoconf流程 — automake(续)
?Makefile.am中的路径定义说明
?

?

管 理 项 目

?

?

尽量使用相对路径,系统预定义了两个基本路径 ? $(top_srcdir):工程最顶层目录,用于引用源程序 ? $(top_builddir):生成目标文件上最上层目录,用于引 用.o等编译出来的目标文件 其它预定义目录 ? bindir = $(prefix)/bin, libdir = $(prefix)/lib, datadir = $(prefix)/share, sysconfdir = $(prefix)/etc 标准安装路径 ? $(prefix) = /usr/local:所有安装目录的默认前缀 ? 覆盖方法:./configure --prefix=<new_prefix> 定义新安装路径(举例) ? 先定义confdir = $(prefix)/config, ? 然后conf_DATA = file1 file2
? file1, file2会作为数据文件安装到$(prefix)/config目录下

121

Linux make

autoconf流程 — automake(续)
?automake支持的目录层次
? ? ?

管 理 项 目

flat:所有文件都位于同一个目录中 shallow:主要源代码储存在顶层目录,其他各个部分则 储存在子目录中 deep:所有源代码都被储存在子目录中 ? 顶层目录主要包含配置信息 ? 所有源文件及自己写的头文件位于当前目录的一个子 目录中,而当前目录里没有任何源文件

122

Linux make

autoconf流程 — automake(续)
?automake命令操作方式
? ?

automake --add-missing 生成生成 Makefile.in, depcomp, install-sh, 和 missing AUTOMAKE_OPTIONS=foreign //必须 bin_PROGRAMS=hello //产生bin文件名 hello_SOURCES=hello.c //指定原文件

管 理 项 目

123

Linux make

autoconf流程 — autoconf
?根据configure.in文件生成configure脚本
?

该脚本可搜集有关移植性的平台相关信息 ? 这些信息被用来生成Makefile ? 生成的Makefile包含许多常用目标,如check, all, install, uninstall, clean, dist … ? autoconf需要用到 m4,便于生成脚本
autoscan configure.scan edit configure.in aclocal autoconf configure aclocal.m4

管 理 项 目

124

Linux make

Src code

autoheader automake Makefile.am Makefile.in

./configure Makefile

GNU make项目示例:Hello World
?步骤1:编辑源文件hello.c
#include <stdio.h> int main() { printf(―Hello World!\n‖); return 0; }

管 理 项 目

125

Linux make

?步骤2:生成configure脚本
? ?

执行autoscan,生成configure.scan 编辑修改configure.scan,生成configure.in
AC_INIT(hello.c) AM_INIT_AUTOMAKE(hello, 0.1) AC_PROG_CC AC_OUTPUT(Makefile)

? ?

执行aclocal,生成aclocal.m4文件 执行autoconf,生成configure脚本

GNU make项目示例:Hello World(续)
?步骤3:创建Makefile.in
?

编辑Makefile.am
AUTOMAKE_OPTIONS=foreign bin_PROGRAMS = hello hello_SOURCES = hello.c

?步骤4:执行./configure,生成makefile 管 ?步骤5:执行make
理 项 目
? ?

126

Linux make

?

执行automake,生成Makefile.in

make install:安装 make dist:产生安装包

主要内容
?Linux简介 ?Linux内核环境 ?Linux编程环境 ?GNU make管理项目 的 ?Linux的程序执行机制
程 序 执 行 机 制 Linux

127

Linux中的请求处理过程
在控制台下输入ls命令 Shell程序分析输入参 数,确定这是ls命令 调用fork系统调用生成 一个shell本身的拷贝 调用exec系统调用将ls 的可执行文件装入内存
从系统调用返回 为什么我们敲击键盘 就会在终端上显示? 中断的概念,终端 控制台设备驱动的 概念 保护模式和实模式: 什么是系统调用? 内存保护,内核态用 户态相关问题 软中断、异常的概念: 系统调用是怎 陷阱门,系统门 么实现的?

的 程 序 执 行 机 制

128

Linux

进程的描述, fork是什么? 进程的创建 内存管理模块,进程的地址空间, 为什么要调用fork? 分页机制,文件系统 如何做到正确的返回? 进程的调度,运行队列 等待队列的维护 堆栈的维护,寄存 器的保存与恢复

Shell和ls都得以执行

CPU执行指令角度
idle 系统调用处理

进程管理 中断处理

的 程 序 执 行 机 制

CPU
intr
idtr

esp eip

内核其他模块

eip esp Wakeup progress cs ds等等 esp 0xc0000000

wait keyborad queue

进程x

129

Linux

some action 8259 c=gets() … main keyboard 进程x esp

从内存角度
0xffffffff 0xe0000000

的 程 序 执 行 机 制
用户代码或数据

130

Linux

0x20000000 (512M) 0xc0000000 (3G)

0x00400000 0x00000000

内核代码 内核静态数据

物理内存

0x00000000

虚拟空间

堆栈
?堆栈是记录C程序运行时调用路径和参数的空间
? ?

?
?

的 ? 程 序 ?C语言编译器对堆栈的使用有一套规则 执 行 ?堆栈运行机制的意义 ? 理解操作系统一些关键性代码的基础 机 制

函数调用框架 传递参数 保存返回地址 提供局部变量空间 ……

131

Linux

堆栈相关寄存器
?esp:堆栈指针(stack pointer)
?

指向系统栈最上面一个栈帧的栈顶

?ebp:基址指针(base pointer)
?
?

的 ?eip:指令寄存器(extended instruction pointer) 程 ? 指向下一条等待执行的指令地址 序 执 行 机 制

132

Linux

指向系统栈最上面一个栈帧的底部 在C语言中记录当前函数调用基址

cs:eip的寻址方式
?总是指向下一条的指令地址
? ?

? ? ? ?

的 程 序 执 行 机 制

顺序执行:总是指向地址连续的下一条指令 跳转/分支:执行这样的指令的时候,cs : eip的值会根据 程序需要被修改 call:将当前cs : eip的值压入栈顶,cs : eip指向被调用函 数的入口地址 ret:从栈顶弹出原来保存在这里的cs : eip的值,放入cs : eip中 发生中断时??? ????

133

Linux

堆栈操作
? push
?

以字节为单位将数据( 4个字节)压入 栈,从高到低按字节依次将数据存入 ESP-1、ESP-2、ESP-3、ESP-4的地址 单元

低地址 esp esp

的 ? 过程与PUSH相反 程 ? call 序 ? 调用一个函数或过程 执 ? 此时下一条指令地址会被压入堆栈,以 行 便返回时能恢复执行下条指令 ebp 机 制 ? ret
? ? ?

134

Linux

? pop

高地址

从一个函数或过程返回 之前call保存的下条指令地址会从栈内 弹出到EIP寄存器中 程序转到CALL之前下条指令处执行

利用堆栈实现函数调用和返回
//建立被调用者函数的堆栈框架 pushl %ebp movl %esp, %ebp // 调用者 … call target …

的 程 序 执 行 机 制

135

Linux

//被调用者函数体 //do sth. …
//拆除被调用者函数的堆栈框架 movl %ebp,%esp popl %ebp ret
将地址A恢复到eip中

call指令 1)将下一条指令的地址A保存 在栈顶 2)设置eip指向被调用程序代 码开始处

函数堆栈框架的形成
? 执行call XXX之前
? ?

cs : eip原来的值指向call下一条指令, 该值被保存到栈顶 然后cs : eip的值指向xxx的入口地址

esp ebp esp esp esp ebp cs : eip 低地址

? 第一条指令: pushl %ebp 的 ? 保存调用者的栈帧地址 程 ? 第二条指令: movl %esp, %ebp 序 ? 初始化XXX的栈帧地址 执 行 ? 函数体中的常规操作,可能会压栈、出栈 机 ? 退出XXX 制 ? movl %ebp, %esp ? ?

136

Linux

? 进入 XXX

ebp 高地址

popl %ebp ret

堆栈其他作用
?C语言中还使用堆栈进行
? ?

参数传递 局部变量的使用

的 程 序 执 行 机 制

137

Linux

编译方法 1)首先使用gcc生成test.c的可执 行文件test; 2)然后使用objdump –S获得test 的反汇编文件;

观察p2的堆栈框架
?从test的反汇编文件中找到p2的反汇编代码
int p2(int x, int y) { push %ebp mov %esp,%ebp return x+y; mov 0xc(%ebp),%eax add 0x8(%ebp),%eax } pop %ebp ret

的 程 序 执 行 机 制

138

Linux

建立框架 ebp esp esp ebp x y 调用者 堆栈 框架 拆除框架 ebp 低地址

高地址

GNU规则规定:%eax、%ecx和%edx是由调用者负责存储的; %ebx、%ebi和%esi则由被调用者保护。

观察main函数是如何传递参数给p2的
… z=p2(x,y); pushl 0xfffffff8(%ebp) pushl 0xfffffff4(%ebp) call 804839b <p2> mov %eax,0xfffffffc(%ebp) printf("%d=%d+%d\n",z,x,y); pushl 0xfffffff8(%ebp) pushl 0xfffffff4(%ebp) pushl 0xfffffffc(%ebp) push $0x8048510 call 80482b0 <printf@plt>

139

esp 被调用者 堆栈 框架 ebp ebp cs:eip x的值 y的值 调用者 堆栈 框架 低地址

的 程 序 执 行 机 制

Linux

esp esp esp

ebp
高地址

p2的返回值是如何返回给main的?

程序改进

的 程 序 执 行 机 制

140

Linux

改进程序中,main函数中调 用了函数p2,而在p2的执行 过程中又调用了函数p1

观察程序运行时堆栈的变化

eip
p1 p1

的 程 序 执 行 机 制

141

Linux

esp
p1堆栈 eip c p2堆栈

eip eip eip eip eip eip eip eip

P2 … p1(c) … main … p2(x,y) …

p2

esp

eip
main

esp

x,y main堆栈 堆栈

程序的代码段

观察堆栈在内核中的使用
?在内核代码中经常有这样的函数,其参数为 struct pt_regs *regs
?

的 程 序 执 行 机 制

?

可以往回一层层的寻找这个参数是怎么传递过来的,最 后可发现最源头的函数使用参数struct pt_regs regs,如 ? 如void do_IRQ(struct pt_regs regs) 如果再进一步寻找是谁调用了这个do_IRQ,会发现只是 一条简单的汇编语句 ? call do_IRQ

142

Linux

pt_regs作用
?用户态 vs. 内核态 ?寄存器上下文
?

从用户态切换到内核态时 ? 必须保存用户态的寄存器上下文

的 ?中断int指令会在堆栈上保存一些寄存器的值,如 程 ? 用户态栈顶地址 序 ? 当时的状态字 执 ? 当时的cs:eip的值 行 机 制

143

Linux

pt_regs结构定义
struct pt_regs { long ebx; long ecx; long edx; long esi; long edi; long ebp; long eax; int xds; int xes; long orig_eax; long eip; int xcs; long eflags; long esp; int xss; }; 1. SAVE_ALL 和 RESTORE_ALL 保 存和恢复的寄存器 2. 异常处理函数中的 Error_code 为保 持一致而保存的数

的 程 序 执 行 机 制

144

Linux

1. 中断(狭)和系统调用保存的中断 号和系统调用号 2. 或者,CPU 为产生硬件错误码的异 常保存的硬件错误码 3. 或者,为保持一致,在异常处理函 数中,随便保存的一个无效的数

CPU 在进入中断或者异常前自动 保存的寄存器

SAVE_ALL和RESTORE_ALL

的 程 序 执 行 机 制

145

Linux

SAVE_ALL()及RESTORE_ALL()
用户空间 内核空间 内核堆栈中的变化 压入用户ss 压入用户esp 压入EFLAGS 压入 cs 压入 eip
(system_call): (system_call): pushl %eax pushl %eax SAVE_ALL SAVE_ALL …… …… …… ……

注解

…… …… int 0x80 int 0x80

由于是陷入进来 内核的,所以机 器自动保存与转 换堆栈。

的 程 序 执 行 机 制

146

Linux

压入
pushl pushl pushl pushl pushl pushl pushl pushl pushl

eax
%es; %ds; %eax; %ebp; %edi; %esi; %edx; %ecx; %ebx

…… …… RESTORE_ALL RESTORE_ALL

popl popl popl popl popl popl popl popl popl addl iret

%ebx; %ecx; %edx; %esi; %edi; %ebp; %eax; %ds; %es; $4,%esp

等价于弹出eax 弹出eip 弹出cs 弹出EFLAGS 弹出用户esp 弹出用户ss

回到用户空间

实验题
?在ubuntu环境下,下载最新版本内核,编译并生成 自定义的内核 ?基于操作系统大作业,采用autoconf框架,生成相 应的Makefile.in和configure脚本 ?编写一个C语言程序(至少包含两个函数调用及若 干个局部变量)
?
?

编译并生成汇编指令 分析程序运行过程中堆栈变化情况

147

《操作系统原理与实践》 第1讲 Linux系统分析基础

叶保留
yebl@nju.edu.cn

南京大学计算机科学与技术系


相关文章:
linux系统及编程基础课后答案
linux系统及编程基础课后答案_工学_高等教育_教育专区。清华大学出版社第...(6)可以单步逐行执行代码,观察程序的运行状态; (7)分析崩溃程序产生的 core ...
Linux基础及应用习题解析
接口上主盘的第五个分区 D、IDE0 接口上从盘的扩展分区 9、系统引导的过程一般包括如下几步: (1)MBR 中的引导装载程序启动; (2) 用户登录; (3)Linux ...
Linux系统分析工具之slabtop
Linux系统分析工具之slabtop_电脑基础知识_IT/计算机_专业资料。一、简介 slabtop - display kernel slab cache information in real time(实时的显示内核 slab ...
LINUX系统grub常见错误分析
LINUX系统grub常见错误分析_电脑基础知识_IT/计算机_专业资料。LINUX系统grub常见错误分析文档原创稿件由 http://www.mdayday.com 站长提供,下载使用请保留署名。 1...
Linux操作系统源代码详细分析
Linux操作系统源代码详细分析_IT/计算机_专业资料。linux内核的代码分析Linux...由于 Linux 是在 Unix 的基础上发展而来的,我们的话题就从 Unix 开始。 Unix...
Linux系统及编程基础习题答案
Linux系统及编程基础习题答案_工学_高等教育_教育专区。第1章 Linux 基础及安装...(6)可以单步逐行执行代码,观察程序的运行状态; (7)分析崩溃程序产生的 core ...
Linux基础及应用习题解析
、Linux 不需要付费 B、Linux 发行商不能向用户收费 C、 Linux 可自由修改和发布 D、只有 Linux 的作者才能向用户收费 2、Linux 系统各组成部分中哪一项是基础...
Linux系统的安全检测与增强技术分析
Linux系统的安全检测与增强技术分析_电脑基础知识_IT/计算机_专业资料。龙源期刊网 http://www.qikan.com.cn Linux 系统的安全检测与增强技术分析 作者:乌兰图亚 ...
Linux操作系统入门基础知识教程
Linux操作系统入门基础知识教程_电脑基础知识_IT/计算机_专业资料。Linux 操作系统入门基础知识教程 2008-09-08 13:48 开篇辞:我很想用用这个操作系统, 可是家...
Linux系统调用过程分析
Linux 系统调用分析计算机 962 班 周从余 一. 与系统调用有关的一些基本知识 1.系统调用的定义在 OS 的核心中都设置了一组用于实现各种系统共能的子程序,并将...
更多相关标签: