深入理解计算机系统(CSAPP)
  • 本电子书信息
  • 出版信息
    • 出版者的话
    • 中文版序一
    • 中文版序二
    • 译者序
    • 前言
    • 关于作者
  • 第 1 章:计算机系统漫游
    • 1.1 信息就是位 + 上下文
    • 1.2 程序被其他程序翻译成不同的格式
    • 1.3 了解编译系统如何工作是大有益处的
    • 1.4 处理器读并解释储存在内存中的指令
    • 1.5 高速缓存至关重要
    • 1.6 存储设备形成层次结构
    • 1.7 操作系统管理硬件
    • 1.8 系统之间利用网络通信
    • 1.9 重要主题
    • 1.10 小结
  • 第一部分:程序结构和执行
    • 第 2 章:信息的表示和处理
      • 2.1 信息存储
      • 2.2 整数表示
      • 2.3 整数运算
      • 2.4 浮点数
      • 2.5 小结
      • 家庭作业
    • 第 3 章:程序的机器级表示
      • 3.1 历史观点
      • 3.2 程序编码
      • 3.3 数据格式
      • 3.4 访问信息
    • 第 4 章:处理器体系结构
    • 第 5 章:优化程序性能
    • 第 6 章:存储器层次结构
  • 第二部分:在系统上运行程序
    • 第 7 章:链接
      • 7.1 编译器驱动程序
      • 7.2 静态链接
      • 7.3 目标文件
      • 7.4 可重定位目标文件
      • 7.5 符号和符号表
      • 7.6 符号解析
      • 7.7 重定位
      • 7.8 可执行目标文件
      • 7.9 加载可执行目标文件
      • 7.10 动态链接共享库
      • 7.11 从应用程序中加载和链接共享库
      • 7.12 位置无关代码
      • 7.13 库打桩机制
      • 7.14 处理目标文件的工具
      • 7.15 小结
      • 家庭作业
    • 第 8 章:异常控制流
      • 8.1 异常
      • 8.2 进程
      • 8.3 系统调用错误处理
      • 8.4 进程控制
      • 8.5 信号
      • 8.6 非本地跳转
      • 8.7 操作进程的工具
      • 8.8 小结
      • 家庭作业
    • 第 9 章:虚拟内存
      • 9.1 物理和虚拟寻址
      • 9.2 地址空间
      • 9.3 虚拟内存作为缓存的工具
      • 9.4 虚拟内存作为内存管理的工具
      • 9.5 虚拟内存作为内存保护的工具
      • 9.6 地址翻译
      • 9.7 案例研究:Intel Core i7 / Linux 内存系统
      • 9.8 内存映射
      • 9.9 动态内存分配
      • 9.10 垃圾收集
      • 9.11 C 程序中常见的与内存有关的错误
      • 9.12 小结
      • 家庭作业
  • 第三部分:程序间的交互和通信
    • 第 10 章:系统级 I/O
      • 10.1 Unix I/O
      • 10.2 文件
      • 10.3 打开和关闭文件
      • 10.4 读和写文件
      • 10.5 用 RIO 包健壮地读写
      • 10.6 读取文件元数据
      • 10.7 读取目录内容
      • 10.8 共享文件
      • 10.9 I/O 重定向
      • 10.10 标准 I/O
      • 10.11 综合:我该使用哪些 I/O 函数?
      • 10.12 小结
      • 家庭作业
    • 第 11 章:网络编程
      • 11.1 客户端—服务器编程模型
      • 11.2 网络
      • 11.3 全球 IP 因特网
      • 11.4 套接字接口
      • 11.5 Web 服务器
      • 11.6 综合:TINY Web 服务器
      • 11.7 小结
      • 家庭作业
    • 第 12 章:并发编程
      • 12.1 基于进程的并发编程
      • 12.2 基于 I/O 多路复用的并发编程
      • 12.3 基于线程的并发编程
      • 12.4 多线程程序中的共享变量
      • 12.5 用信号量同步线程
      • 12.6 使用线程提高并行性
      • 12.7 其他并发问题
      • 12.8 小结
      • 家庭作业
  • 附录 A:错误处理
  • 参考文献
  • 实验
    • 实验总览
      • 常见问题
    • 实验 1:Data Lab
      • README(讲师版)
      • README(学生版)
      • Writeup
    • 实验 2:Bomb Lab
      • README(讲师版)
      • Writeup
    • 实验 3:Attack Lab
    • 实验 4:Architechture Lab
    • 实验 5:Cache Lab
    • 实验 6:Performance Lab
    • 实验 7:Shell Lab
    • 实验 8:Malloc Lab
    • 实验 9:Proxy Lab
由 GitBook 提供支持
在本页
  • 练习题 7.6
  • 练习题 7.7
  • 练习题 7.8
  • 练习题 7.9
  • 练习题 7.10
  • 练习题 7.11
  • 练习题 7.12
  • 练习题 7.13
  1. 第二部分:在系统上运行程序
  2. 第 7 章:链接

家庭作业

练习题 7.6

这道题是关于图 7-5 的 m.o 模块和下面的 swap.c 函数版本的,该函数计算自己被调用的次数:

extern int buf[];

int *bufp0 = &buf[0];
static int *bufp1;

static void incr()
{
    static int count=0;

    count++;
}

void swap()
{
    int temp;

    incr();
    bufp1 = &buf[1];
    temp = *bufp0;
    *bufp0 = *bufp1;
    *bufp1 = temp;
}

对于每个 swap.o 中定义和引用的符号,请指出它是否在模块 swap.o 的 .symtab 节中有符号表条目。如果是这样,请指出定义该符号的模块(swap.o 或 m.o)、符号类型(局部、全局或外部)以及它在模块中所处的节(.text、.data 或 .bss)。

符号

swap.o .symtab 条目?

符号类型

定义符号的模块

节

buf

bufp0

bufp1

swap

temp

incr

count

练习题 7.7

不改变任何变量名字,修改 7.6.1 节中的 bar5.c,使得 foo5.c 输出 x 和 y 的正确值(也就是整数 15213 和 15212 的十六进制表示)。

练习题 7.8

在此题中,REF(x,i) → DEF(x,k) 表示链接器将任意对模块 i 中符号 x 的引用与模块 k 中符号 x 的定义相关联。在下面每个例子中,用这种符号来说明链接器是如何解析在每个模块中有多重定义的引用的。如果出现链接时错误(规则 1),写“错误”。如果链接器从定义中任意选择一个(规则 3),那么写“未知”。

A.

(a) REF(main.1) → DEF(____.__)

(b) REF(main.2) → DEF(____.__)

/* Module 1 */    |     /* Module 2 */
int main()        |     static int main=1[
{                 |     int p2()
}                 |     {
                  |     }

B.

(a) REF(x.1) → DEF(____.__)

(b) REF(x.2) → DEF(____.__)

/* Module 1 */    |     /* Module 2 */
int x;            |     double x;
void main()       |     int p2()
{                 |     {
}                 |     }

C.

(a) REF(x.1) → DEF(____.__)

(b) REF(x.2) → DEF(____.__)

/* Module 1 */    |     /* Module 2 */
int x=1;          |     double x=1.0;
void main()       |     int p2()
{                 |     {
}                 |     }

练习题 7.9

考虑下面的程序,它由两个目标模块组成:

/* foo6.c */
void p2(void);

int main()
{
    p2();
    return 0;
}
/* bar6.c */
#include <stdio.h>
char main;
void p2()
{
    printf("0x%x\n", main);
}

当在 x86-64Linux 系统中编译和执行这个程序时,即使函数 p2 不初始化变量 main,它也能打印字符串 “0x48\n” 并正常终止。你能解释这一点吗?

练习题 7.10

a 和 b 表示当前路径中的目标模块或静态库,而 a → b 表示 a 依赖于 b,也就是说 a 引用了一个 b 定义的符号。对于下面的每个场景,给出使得静态链接器能够解析所有符号引用的最小的命令行(即含有最少数量的目标文件和库参数的命令)。

A. p.o → libx.a → p.o

B. p.o → libx.a → liby.a 和 liby.a → libx.a

C. p.o → libx.a → liby.a → libz.a 和 liby.a → libx.a → libz.a

练习题 7.11

图 7-14 中的程序头部表明数据段占用了内存中 0x230 个字节。然而,其中只有开始的 0x228 字节来自可执行文件的节。是什么引起了这种差异?

练习题 7.12

考虑目标文件 m.o 中对函数 swap 的调用(作业题 7.6)。

  9: e8 00 00 00 00      callq e <main+0xe>     swap()

具有如下重定位条目:

r.offset = 0xa
r.symbol = swap
r.type   = R_X86_64_PC32
r.addend = -4

A. 假设链接器将 m.o 中的 .text 重定位到地址 0x4004e0,把 swap 重定位到地址 0x4004f8。那么 callq 指令中对 swap 的重定位引用的值应该是什么?

B. 假设链接器将 m.o 中的 .text 重定位到地址 0x4004d0,把 swap 重定位到地址 0x400500。那么 callq 指令中对 swap 的重定位引用的值应该是什么?

练习题 7.13

完成下面的任务将帮助你更熟悉处理目标文件的各种工具。

A. 在你的系统上,lib.c 和 libm.a 的版本中包含多少目标文件?

B. gcc -Og 产生的可执行代码与 gcc -Og -g 产生的不同吗?

C. 在你的系统上,GCC 驱动程序使用的是什么共享库?

上一页7.15 小结下一页第 8 章:异常控制流

最后更新于4年前