【阅读笔记】深入理解计算机系统
计算机系统漫游
信息的处理及表示
2.1 信息存储
练习 2.2
(十进制) (十六进制) 9 512 0x200 19 524288 0x80000 14 16384 0x4000 1716131072655360x10000 17 131072 0x100000x200005 32 0x10 11 2048 0x800
练习 2.3
十进制 二进制 十六进制 0 0000 0000 0x00 167 1010 0111 0xA7 62 0100 0011 0x43 188 1011 1100 0xBC 55 0011 0111 0x37 1000 1000 1111 0011 525 16 2 820101 0010 0x52 0xAC 0xE7
练习 2.4
十六进制加减法,不得使用进制转换。
A.
0x503c + 0x8 = 0x5044
B.
0x503c - 0x40 = 0x499c
0x503c - 0x40 = 0x4ffc
C.
0x503c + 64 = 0x507c
D.
0x50ea - 0x503c = 0xAD
0x50ea - 0x503c = 0xAE
寻址和字节顺序
练习题 2.5
int val = 0x87654321
小端法 大端法 A 21
87
B 21 43
87 65
C 21 43 65
87 65 43
val
21 43 65 87
87 65 43 21
练习题 2.6
0x00359141 = 0000 0000 0011 0101 1001 0001 0100 0001
0x4A564504 = 0100 1010 0101 0110 0100 0101 0000 0100
1
2
3
4
5 0 0 3 5 9 1 4 1
00000000001101011001000101000001
*********************
01001010010101100100010100000100
4 A 5 6 4 5 0 4
练习题 2.7
1
2 "abcdef" -> (ASCII) 65 66 67 68 69 70
-> (printf) 61 62 63 64 65 66
练习题 2.8
运算 结果 a
01101001
b
01010101
~a
10010110
~b
10101010
a & b
01000001
`a b` 01111101
a ^ b
00111100
练习题 2.10
步骤 *x *y
练习题 2.11
A.
first == last == k
B.
inplace_swap(&a[k], &a[k]);
第一行等价于a[k] = a[k] ^ a[k];
C.
void inplace_swap(int* x, int* y);
第一行加上if(*x == *y) return;
或
line 4
改为first < last
练习题 2.12
A.
x & 0xFF
B.
(~x & ~0xFF) | (x & 0xFF)
C.
x | 0xFF
练习题 2.13
1
2
3
4
5
6
7
8
9
10
11
12
13
14 int bis(int x, int m); //x | m;
int bic(int x, int m); //x & ~m;
//~x = 1 & ~m
int bool_or(int x, int y)
{
int result = bis(x, y);
return result;
}
int boo_xor(int x, int y) //x xor y = x & ~y | ~x & y;
{
int result = bis(bic(x, y), bic(y, x));
return result;
}
练习题 2.15
1
2
3
4 int bool_equal(int x, int y)
{
return ~((x & ~y) | (~x & y));
}
C 语言中的移位运算
-
左移:
x << n
表示二进制位向左移动 位,低位补 。 -
右移:
- 逻辑右移:
x >> n
表示二进制位向左移动 位,高位补 。 - 算术右移:
x >> n
表示二进制位向左移动 位,若 最高位是 ,则高位补 ;若 最高位是 ,则高位补 ;。
- 逻辑右移:
练习 2.16
x x x<<3 x<<3 x>>2(逻辑) x>>2(逻辑) x>>2(算术) x>>2(算术) 十六进制 二进制 二进制 十六进制 二进制 十六进制 二进制 十六进制 0xC3 1100 0011 0001 1000 0011 0000 1111 0000 0x75 0111 0101 1010 1000 0001 1101 1101 1101`` 0001 11010x87 1000 0111 0011 1000 0010 0001 1110 0001 0x66 0110 0110 0011 0000 0001 1001 0001 1001
2.2 整数表示
无符号数编码
对向量
补码编码
对向量
练习题 2.17
十六进制 二进制 0xE 0x0 0x5 0x8 0xD 0xF
练习题 2.18
十六进制 二进制 补码 0x2e0 $2^{10} + 2^8 + 2^7 + 2^6-0x58 2^7 + 2^5 + 2^4<br>
0x28 0x30 0x78 0x88 0x1f8 0x8 0xc0 0x48
有符号数与无符号数之间的转换
练习题 2.19
练习题 2.21
表达式 类型 求值 -2147483647-1 == 2147483648U<br>``0x8000 == 0x8000
无符号 0
1
有符号 1
无符号 0
有符号 1
无符号 1
扩展一个数字的位表示
无符号数转换为一个更大的数据类型:零扩展
补码数数转换为一个更大的数据类型:高位使用 填充
证明(数学归纳法):
1 | short x = -12345; |
练习题 2.23
A.
w
fun1(w)
fun2(w)
0x00000076
0x00000076
0X00000076
0x87654321
0x00000021
0x00000021
0x000000C9
0x000000C9
0xFFFFFFC9
0xEDCBA987
0x00000087
0xFFFFFF87
B.
fun1
实现将 32 位无符号int
转换为 8 位无符号int
,即无符号数对 取模。
fun2
实现将 32 位有符号int
转换为 8 位有符号int
,有符号数的二进制表示取低 位,然后进行有符号扩展。
截断数字
-
无符号数截断:
令向量 , 是将 截断 位的结果。令 , ,则
-
有符号数截断:
其中, 先将有符号数转换成无符号数并用无符号方法截断,然后把无符号数转换成有符号数。
练习题 2.24
十六进制 二进制 无符号 补码 原始值 截断值 原始值 截断值 原始值 截断值 原始值 截断值 0 0 0000 000 0 0 0 0 2 2 0010 010 2 2 2 2 9 1 1001 001 9 1 -7 1 B 3 1011 011 11 3 -5 3 F 7 1111 111 15 7 -1 -1 都先将二进制表示转换为无符号数,然后对 取模截断,所得结果视作 位有/无符号数。
练习题 2.25
传入的
length
为 时,length - 1
为无符号数,值为~0x0
,比较i
与length - 1
的大小时,i
会被转换为无符号数将其比较,设length
是一个k
位无符号数,则i
若视作无符号数,表示范围为 或 ,总之a[i]
将出现越界访问,导致内存错误。解决方法是第 行修改为
for(int i=0; i <= (int)length - 1; i++)
练习 2.26
A.
s
比t
短时,结果不正确。B.
在 A. 的条件下,
strlen(s) - strlen(t)
仍是一个无符号正整数 ,右边的0
将被视作无符号数,返回真。
1
2
3
4 int strLonger(char *s, char *t)
{
return strlen(s) > strlen(t);
}
2.3 整数的运算
练习 2.27
1
2
3
4 int uadd_ok(unsigned x, unsigned y)
{
return x + y >= x;
}
练习题 2.28
十六进制 十进制 十进制 十六进制 0 0 1600 5 5 11 B 8 8 8 8 D 13 133D F 15 1 1
练习题 2.29
情况 <br>
情况 31<br>
情况 2 <br>
情况 12<br>
情况 3 <br>
情况 4
练习题 2.30
1
2
3
4 int tadd_ok(int x, int y)
{
return !((x > 0 && y > 0 && x + y < 0) || (x < 0 && y < 0 && x + y > 0))
}
练习题 2.31
假设发生正溢出,则
sum = x + y - 2^k
,sum - x = y - 2^k
,在模 意义下就是 ,对 同理,所以正溢出时仍然返回真;同理,负溢出也返回真。
练习题 2.32
用
tadd_ok(int x, int y)
来判断 是否溢出:
1
2
3
4 int tsub_ok(int x, int y)
{
return tadd_ok(x, -y);
}这种写法是在假设:对任意 ,若
tsub_ok(x, y)
判断没有溢出,即 由tadd_ok(x, -y)
判断没有溢出,这要求 ,但其实不然。时, ,若 ,则 ,没有发生溢出,但是 ,将被
tadd_ok()
判断为负溢出;若 , ,发生正溢出,而 ,被tadd_ok()
判断为没有溢出。解决方法:
1
2
3
4
5 int tsub_ok(int x, int y)
{
if(y == -y) return x < 0;
else return tadd_ok(x, -y);
}
练习题 2.33
十六进制 十进制 十进制 十六进制 0 0 0 0 5 5 -5 B 8 8-88-88 D -3 3 3 F -1 1 1
无符号乘法
对满足 的 和 :
有符号乘法
对满足 的 和 :
练习题 2.34
模式 截断 无符号 <br>
有符号 <br>
有符号 <br>
无符号 <br>
有符号 <br>
无符号 <br>
练习题 2.35
- 由有符号数乘法的定义,设 , ,则 ,所以 ,即 。
若计算溢出,则 ,又 ,故
若 ,由于 ,且 ,有 ,所以 ,计算溢出。
若 ,则令 , .
若 ,则令 , .
若 ,则由 ,且 ,所以 , , 。
若 ,则 ,易得 。
综上,若没有溢出,则 ,此时 ,
!x || p / x == y
为真。
练习 2.36
1
2
3
4
5 int tmult_ok(int x, int y)
{
int64_t p = x * y;
return p == (int) p;
}
练习 2.37
使用uint64_t
保存ele_cnt * ele_size
的结果,防止溢出导致分配的空间过小,进而防止循环复制时超出缓冲区界限。A. 这个改动没有帮助,因为
malloc
只能接收int32_t
作为参数,仍然可能溢出。B.
1 if(asize != (unit32_t)asize) return NULL;
乘以常数
将 分解为二进制序列 ,则有:
练习题 2.38
可以计算 , 等,即
练习题 2.39
为最高位时,
, ,溢出截断后为x<<(n + 1)
=本身。故改为x - (x << m)
- (x << m)
练习题 2.40
移位 加法/减法 表达式 (x<<3) - (x<<1)
(x<<5) - x
(x<<1) - (x<<3)
(x<<6) - (x<<3) - x
练习题 2.41
视加减法、移位计算的开销决定,选择综合开销最小的那种。
除以 2 的幂
若 是无符号数:
此处使用逻辑右移。
若 是有符号数且大于 ,操作与无符号数相同,但使用算术右移。
若 是有符号数且小于 ,除以 时,要先加上偏置位 ,再算术右移:
练习题 2.42
1
2
3
4 int div16(int x)
{
return !(x & (1 << 31)) * (x >> 4) + (x & (1 << 31)) * ((x + (1 << 4) - 1) >> 4);
}
练习题 2.43
x * M = x * (2^5 - 1)
y = (y < 0 ? (y + (1 << 3) - 1) : y) >> 3 = y / 3
所以
M = 31, N = 2^3 = 8
练习 2.44
A. 若
x > 0 == true
,则为true
若
x > 0 == false
,则x <= 0
,即((x - 1) < 0) == true
B. 若
(x & 7) ==7
,则x
最低三位是111
,x
是 位int
,x << 29
的最高三位是111
,故其小于C. 的最高位恒为 ,因此
x * x >= 0
D. 若
x >= 0
,则根据有符号数的逆元定义,-x <= 0
E. 若 , ,故为假
F. 时,不成立
G.
2.4 浮点数
二进制小数
练习题 2.45
小数值 二进制 十进制
练习题 2.46
A. 是
0.000000000000000000000[0011]
B.
C.
D.
浮点数的表示
用 表示一个浮点数。
- 编码符号位, 为正, 为负。
- 位阶码,表示一个二进制整数 ,用来编码
- 位小数字段,表示一个二进制小数 ,用来编码
情况 1:规格化的值
- 的所有位不全为 或
- , 其中 ,使得双精度指数范围为 ,单精度为
情况 2:非规格化的值
- 阶码字段 所有位全为 ,即
时根据 的取值决定表示 或 ,二者有时候是不同的。
时用来表示非常接近 的数。
情况 3:特殊值
- 阶码字段 所有位全为
- 若 ,表示 或
- 表示 (Not a number)
练习题 2.47
位 十进制 0 00 00
0 00 01
0 00 10
0 00 11
0 01 00
0 01 01
0 01 10
0 01 11
0 10 00
0 10 01
0 10 10
0 10 11
0 11 00
0 11 01
0 11 10
0 11 11
练习题 2.49
A.
B.
舍入
练习题 2.50
A.
B.
C.
D.
练习题 2.51
A. 精确到小数点右边 位,使用舍入到偶数方法得
B.
C.
D.
练习题 2.52
格式 A 格式 B 位 值 位 值 011 0000
0111 000
101 1110
1001 111
010 1001
0110 100
110 1111
1011 000
000 0001
0001 000
练习题 2.53
1
2
3
练习题 2.54
A.
int
转double
没有精度丢失,再转回来也没事B.
x = 0x7fffffff
时,转成float
会舍入,精度下降,甚至比x
大的值,再转回int
会溢出C.
double
转float
精度会丢失D.
float
转double
精度不会丢失E. 浮点数取加法逆元只需要把符号位取反即可,取两次加法逆元符号不变
F. 两侧都会变成
double/double
,且int
转double
精度不丢失,所以值相等G. 浮点数取平方,一定为正数,且大于等于
H. 若
f + d
溢出double
最大规格化数值成inf
,则f + d - f
为inf
第 3 章 程序的机器级表示
3.4 访问信息
x86_64 寄存器:
格式为 的操作数格式表示的操作数为
练习题 3.1
操作数 | 值 |
---|---|
%rax |
0x100 |
0x104 |
0xAB |
0x108 |
0x13 |
(%rax) |
0xFF |
4(%rax) |
0xAB |
9(%rax, %rdx) |
0x11 |
260(%rcx, %rdx) |
0x13 |
0xFC(, %rcx, 4) |
0xFF |
(%rax, %rdx, 4) |
0x11 |
练习题 3.2
movl %eax, (%rsp)
movw (%rax), %dx
movb $0xFF, %bl
movb (%rsp, %rdx, 4), %dl
movq (%rdx), %rax
movw %dx, (%rax)
练习题 3.3
movb $0xF, (%ebx)
:%ebx
不可以作为内存引用
movl %rax, (%rsp)
:%rax
是四字,应该用 movq
movw (%rax), 4(%rsp)
:两个操作数都指向内存
movb %al, %sl
:似乎不存在 %sl
寄存器
movq %rax, $0x123
:目的操作数不能是立即数
movl %eax, %rdx
:目的寄存器大小应该和 %rax
保持一致,即 edx
movb %si, 8(%rbp)
:%si
是双字,应该用 movw
练习题 3.4
movzbl (%rdi), %eax
movb %eax, (%rsi)
movzbl (%rdi), %eax
movsbl (%rdi), %eax
movb %eax, (%rsi)
movzbq (%rdi), %rax
mob %rax, (%rsi)
movl (%rdi), %eax
movb %al, (%rsi)
movl (%rdi), %eax
movb %al, (%rsi)
movzbw (%rdi), %ax
movw %ax, (%rsi)
练习题 3.5
1 | void decode1(long *xp, long *yp, long *zp) |
练习题 3.6
6 + (x mod 2^16)
x + y
x + 4y
7 + 9x
0xA + 4y
9 + x + 2y
练习题 3.7
5x + 2y + 8z
练习题 3.8
0x100
0x11
0x108
0xA8
0x118
0x110
0x110
0x14
%rcx
0x0
%rax
0xFD
练习题 3.9
movl %rdi, %rax
salq $4, %rax
movb (%rsi), %cl
movq (%esi), %rcx
sarq %cl, %rax
练习题 3.10
1 | long t1 = x | y; |
练习题 3.11
A. 将 %rdx
所有位置 0
B. movq $0, %rdx
C.
练习题 3.12
1 | urerndiv: |
练习题 3.13
A. int <
B. short >=
C. unsigned char <=
D. long long !=
练习题 3.14
A. long long >=
B. short/unsigned short ==
C. unsign char <=
D. int !=
练习题 3.15
A. 0x4003fe
B. 0x400521
C. 0x400543 0x400545
D. 0x400560
练习题 3.16
1 | void cond_goto(long a, long *p) |
该判断条件由两个子条件构成,任意一个条件不满足函数都将返回,因此需要两个分支语句。
练习题 3.17
1 | long gotodiff_se2(long x, long y) |
选用本例中的方法代码更加清晰易读,但是可能产生额外的转跳。
练习题 3.18
1 | long test(long x, long y, long z) |
练习题 3.19
A.
B.
练习题 3.20
1 | long arith(long x) |
OP
表示除法 /
练习题 3.21
1 | long test(long x, long y) |
1 | long test(long x, long y) |
练习题 3.23
A.
1 | %rax -> x |
B.
(*p)++
表示令 x+=1
,则在第 7
行与 x += y
一起计算.
C.
1 | dw_loop: |
练习题 3.24
1 | long loop_while(long a, long b) |
练习题 3.25
1 | long loop_while2(long a, long b) |
练习题 3.26
1 | long fun_a(unsigned long x) |
练习题 3.27
1 | long fact_for(long n) |
练习题 3.28
1 | long fun_b(unsigned long x) |
练习题 3.29
A.
1 | long sum = 0; |
B.
1 | long sum = 0; |
练习题 3.30
A.
1 | void switch2(long x, long *dest) |
B. L5
L7
L2
均有多个标号。
练习题 3.31
1 | void switcher(long a, long b, long c, long *dest) |
3.7 过程
练习题 3.32
指令 | 状态值 | (指令 | 执行 | 前) | ||||
---|---|---|---|---|---|---|---|---|
标号 | PC | 指令 | %rdi |
%rsi |
%rax |
%rsp |
*%rsp |
描述 |
M1 |
0X400560 |
callq |
10 |
-- |
-- |
0x7fffffffe820 |
-- |
调用first(10) |
F1 |
0x400548 |
lea |
10 |
-- |
-- |
0x7fffffffe828 |
0x400565 |
调用lea |
F2 |
0x40054c |
sub |
10 |
11 |
-- |
0x7fffffffe828 |
0x400565 |
|
F3 |
0x400550 |
callq |
9 |
11 |
-- |
0x7fffffffe828 |
0x400565 |
|
L1 |
0x400540 |
mov |
9 |
11 |
-- |
0x7fffffffe830 |
0x400555 |
|
L2 |
0x400543 |
imul |
9 |
11 |
11 |
0x7fffffffe830 |
0x400555 |
|
L3 |
0x400547 |
retq |
9 |
11 |
99 |
0x7fffffffe830 |
0x400555 |
|
F4 |
0x400555 |
repz |
9 |
11 |
99 |
0x7fffffffe828 |
0x400565 |
|
M2 |
0x400565 |
mov |
9 |
11 |
99 |
0x7fffffffe820 |
-- |
练习题 3.33
(int a, short b, long long *u, char*v)
(int b, short b, long long *v, char*u)
练习题 3.34
A. a0 ... a5
存储在被调用者保存及寻求
B. a6, a7
存储在栈上
C. 因为被调用者保存寄存器总共只有 个
练习题 3.35
A. 是参数 x
B.
1 | long rfun(unsigned long x) |
3.8 数组
练习 3.36
数组 | 元素大小 | 整个数组的大小 | 起始地址 | 元素 |
---|---|---|---|---|
s |
||||
T |
||||
U |
||||
V |
||||
w |
练习题 3.37
short* |
leal 2(%rdx), %rax |
||
short |
mov 6(%rdx), %al |
||
short* |
leal (%rdx, %rcx, 2), %rax |
||
short |
mov 2(%rdx, %rcx, 8), %al |
||
short* |
leal -10(%rdx, %rcx, 2), %rax |
练习题 3.38
M(P + 8(7i + 5j)) + M(Q + 8(i + 5j))
得 N = 7
M = 1
练习题 3.39
T D[R][C]
D[i][j] = *(D + L(C * i + j))
&A[i][0] = A + 4 * (16 * i) = 64i
&B[0][k] = B + 4 * (k) = B + 4k
&B[N][k] = B + 4 * (N * 16 + k) = B + 4k + 1024
练习题 3.40
1 | void fix_set_diag_opt(fix_matrix A, int val, int N) |
3.9 异质的数据结构
练习题 3.41
A.
p: 0
s.x: 8
s.y: 12
next: 16
B.
24
C.
1 | void sp_init(struct prob *sp) |
练习题 3.42
A.
1 | long fun(struct ELE *ptr) |
B.
遍历以 ELE
为头节点的链表,求 v
的和。
练习题 3.43
代码 | ||
---|---|---|
short |
movw 8(%rdi), %ax movw %ax, (%si) |
|
char* |
addq \$10, %rdi movq %rdi, (%rsi) |
|
int* |
movq %rdi, (%rsi) |
|
int |
movq (%rdi), %rax movl (%rdi, %rax, 4), %eax movl %eax, (%rsi) |
|
char |
movq 8(%rdi), %rax movb (%rax), %al movb %al, (%rsi) |
练习题 3.44
A.
1 | 0 4 8 12 |
B.
1 | 0 4 5 8 |
C.
1 | 0 2 4 6 7 8 |
D.
1 | 0 2 4 6 8 16 24 32 |
E.
1 | 0 10 24 |
练习题 3.45
A.
1 | a b c d e f g h |
B.
C.
1 | a c g e h b d f |
优化后需要填充至 确保下一个实例内存对齐,故大小为
3.10 在机器级程序中将控制与数据结合起来
练习题 3.46
A.
1 | 00 00 00 00 00 40 00 76 返回地址 |
B.
1 | 00 00 00 00 00 40 00 34 返回地址 |
C.
返回到 0x00 40 00 34
D.
%rbx
被破坏了,它的值会被加载为 0x33 32 31 30 39 38 37 36
E.
malloc
函数调用时应该分配 len(buf)+1
长度的内存来容纳字符串结尾的 \0
,同时还应该检查 result
是否为 NULL
练习题 3.47
A. 大约 个
B. 128
字节即 ,使得只需要 次尝试。
练习题 3.48
A.
不带保护:
buf
在 %rsp
,v
在 %rsp+24
带保护:
buf
在 %rsp+16
,v
在 %rsp+8
,金丝雀值在 %rsp+40
B.
v
比 buf
更靠近栈顶,使得溢出更不容易影响到 buf
练习题 3.49
A.
首先将 %rax
设为 ,接着让它 &
-16
,等价于让其向下舍入到最接近的 16
的倍数,保证内存对齐。得到 的值
B.
先将 %rsp
加 ,而后除以 再乘以 ,可向上舍入到最近的 的倍数,得到 p
的值。
C.
对应最大化与最小化 的情况。
D.
实现 的 字节对齐, 的 字节对齐。
第 4 章 处理器的体系结构
4.1 Y86-64 指令集体系结构
练习题 4.1
1 | 0x100: 30f30f00000000000000 |
练习题 4.2
A.
1 | 0x100: 30f3fcffffffffffffff irmovq $-4, %rbx |
B.
1 | 0x200: a06f push %rsi |
练习题 4.4
1 | .x86-64 |
1 | .y86 |
练习题 4.5
1 | sum: |
练习题 4.6
1 | sum: |
4.2 逻辑设计和硬件语言控制 HCL
练习题 4.9
1 | bool xor = (!a && b) || (a && !b); |
练习题 4.10
按位 xor
,将所有结果取 and
,再取 not
.
练习题 4.11
1 | word Min3 = [ |
练习题 4.12
1 | word Mid3 = [ |
4.3 Y86-64 的顺序实现
练习题 4.13
阶段 | 通用 | 具体 |
---|---|---|
irmoq V, rB |
irmovq $128, %rsp |
|
取指 | icode:ifun <- M_1[0x016] = 3:0 rA:rB <- M_1[0x017] = f:4 valC <- M_8[0x018] = 128 valP <- 0x020 |
|
译码 | ||
执行 | valE <- 128 |
|
访存 | ||
写回 | R[rB] <- 128 |
|
更新 PC | PC <= 0x020 |
练习题 4.14
0x02c: b00f
%rsp = 0x120
阶段 | 通用 | 具体 |
---|---|---|
popq rA |
popq %rax |
|
取指 | icode:ifun <- M_1[0x02c] = b:0 rA:rB <- m_1[0x02d] = 0:f valP <- 0x02e |
|
译码 | valA <- R[%rsp] = 0x120 valB <- R[5rsp] = 0x120 |
|
执行 | valE <- valB + 8 = 0x128 |
|
访存 | valM <- M_8[0x120] = 9 |
|
写回 | R[%rsp] <- valE = 0x128 R[rA] <- valM = 9 |
|
更新 PC | PC <- valP = 0x02e |
练习题 4.15
将 %rsp
变更前 %rsp
的值写入%rsp
变更后指向的栈顶内存中
练习题 4.16
将 %rsp
变更前栈顶的值写入 %rsp
练习题 4.17
阶段 | cmovXX rA, rB |
---|---|
取指 | icode:ifun <- M_1p[PC] rA:rB <- M-1[PC+1] valP <- PC + 2 |
译码 | valA <- R[rA] |
执行 | valE <- 0 + valA Cnd <- Cond(CC, ifun) |
写回 | R[rB] <- valE |
更新 PC | PC <- valP |
练习题 4.18
0x037: 804100000000000000
阶段 | 通用 | 具体 |
---|---|---|
call Dest |
call 0x041 |
|
取指 | icode:ifun <- M_1[0x037] = 8:0 valC <- 0x041 valP <- 0x037+9 = 0x040 |
|
译码 | valB <- R[%rsp] = 0x128 |
|
执行 | valE <- valB + (-8) = 0x120 |
|
访存 | M_8[valE] <- valP = 0x040 |
|
写回 | R[%rsp] <- valE = 0x120 |
|
更新 PC | PC <- valC = 0x041 |
练习题 4.19
1 | bool need_valC = icode in {IIRMIVQ, IRMMOVQ, IMRMOVQ, ICALL, IJXX} |
练习题 4.20
1 | word srcB = [ |
练习题 4.22
由 练习题 4.8 知 popq %rsp
最终将写入内存的值,因此 M
口的优先级应该更高.
练习题 4.24
1 | word dstE = [ |
4.4 流水线的通用原理
练习题 4.28
A. C
与 D
之间,延迟为 ,一个时钟周期为
B.
练习题 4.29
A.
B.
4.5 Y86-64 d的流水线实现
第 5 章 优化程序性能
5.1 优化编译器的能力和局限性
练习题 5.1
若 xp
和 yp
在同一个位置。
1 | void swap(long *xp, long *xp) |
5.4 消除循环的低效率
练习题 5.3
代码 | min |
max |
incr |
square |
---|---|---|---|---|
A | ||||
B | ||||
C |
练习题 5.4
A. 在第一个循环中 %xmm0
是临时值,被初始化为 %rbx
的值,每次循环结束后写回 %rbx
,第二个循环中 %xmm0
是累计值。
B. 与 combine3
行为相同。
C. 因为除了每次循环开头没有 将 %rbx
指向内存传给 %xmm0
,其他都一样,而 %xmm0
本身就是累计值,在循环开始前就初始化为 IDENT
了。
练习题 5.5
A.
加法: 次
乘法: 次
B.
乘法: 次
5.9 提高并行性
**练习题 5.8 ? **
A1:
A2:
A3:
A4:
A5:
5.11 一些限制因素
练习题 5.9
1 | int take = src1[i1] < src2[i1]; |
练习题 5.10
A.
将数组变为: 2, ..., 1000
B.
将数组变为: 1, ..., 1
C.
A 情况中所有循环不想关,可以独立执行; B 情况中,前后迭代存在读/写相关,将导致性能下降。
D.
与情况 A 相同,因为相邻迭代不存在数据相关。
练习题 5.11
相邻的迭代存在数据相关,因此形成了 “存储——加载——加法” 的关键路径,导致性能下降。
练习题 5.12
1 | void psumv(float *a, int len, float *p) |
第 6 章 存储器层次结构
6.1 存储技术
练习题 6.1
越接近正方形需要的地址位越少。
组织 | max(b_r, b_c) |
||||
---|---|---|---|---|---|
练习题 6.2
练习题 6.3
平均旋转延迟:
平均传送时间:
总时间:
练习题 6.4
A.
读 个逻辑块,这也是扇区数,最优情况是寻到后立刻开始读取数据,且数据在同一个柱面上,需要旋转两圈来读取所有数据。
旋转一圈时间:
总时间:
B.
每个块都随机分布在磁盘上,每次都要
共
练习题 6.5
A.
B.
C.
练习题 6.6
每 GB 价格
大约 年可以实现。
6.2 局部性
练习题 6.7
1 | sum += a[i][j][k] |
练习题 6.8
设
数据布局为:
1 | 地址 0 4 8 12 16 20 24 28 32 36 40 44 |
clear1
1 | 地址 0 4 8 12 16 20 24 28 32 36 40 44 |
clear2
1 | 地址 0 4 8 12 16 20 24 28 32 36 40 44 |
clear3
1 | 地址 0 4 8 12 16 20 24 28 32 36 40 44 |
空间局部性从好到差:clear1 clear2 clear3
clear1
顺序访问,clear2
以步长为 转跳,clear3
以步长为 转跳。
6.4 高速缓存存储器
练习题 6.9
高速缓存 | ||||||||
---|---|---|---|---|---|---|---|---|
1. | ||||||||
2. | ||||||||
3. |
练习题 6.10
由于消除了抖动,下列标记为 的是命中的, 为不命中。
1 | 0 1 2 3 4 5 6 7 |
因此命中率为
练习题 6.11
A. 相同组索引的块被映射到同一个高速缓存,缓存内每个块的标记位有 位,因此一个 chunk 有 个块。
B. ,因此 ,当使用高 位来作为组索引时,数组中所有块都会被映射到组 ,任意时刻缓存中数组的块数都是
练习题 6.12
12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
CT | CT | CT | CT | CT | CT | CT | CT | CI | CI | CI | CO | CO |
练习题 6.13
A.
12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
B.
参数 | 值 |
---|---|
CO | 0x0 |
CI | 0x5 |
CT | 0x71 |
命中? | 是 |
返回字节 | 0xB |
练习题 6.14
A.
12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
B.
参数 | 值 |
---|---|
CO | 0x1 |
CI | 0x5 |
CT | 0x6E |
命中? | 否 |
返回字节 | -- |
练习题 6.15
A.
12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 |
B.
参数 | 值 |
---|---|
CO | 0x0 |
CI | 0x1 |
CT | 0xFF |
命中? | 否 |
返回字节 | -- |
练习题 6.16
1 | 0000 0110 0100 1100 0x064C |
6.5 编写高速缓存友好的代码
练习题 6.27
A.
dst
0 | 1 | |
---|---|---|
0 | m | m |
1 | m | m |
src
0 | 1 | |
---|---|---|
0 | m | m |
1 | m | h |
B.
dst
0 | 1 | |
---|---|---|
0 | m | h |
1 | m | h |
src
0 | 1 | |
---|---|---|
0 | m | h |
1 | m | h |
练习题 6.19
A.
B. 缓存一行能存储两个元素,每隔两次读就会出现一次缓存不命中,共 次。
C.
练习题 6.20
A.
B. 读取每一个 grid[j][i].x
都会缓存不命中,读取 grid[j][i].y
缓存会命中,共不命中 次。
C.
D. 能存下整个数组,只存在冷不命中,不命中率为
练习题 6.21
A.
B. 每两次读取 grid[i][j].x
会出现一次缓存不命中,而读取所有的 grid[i][j].y
缓存命中,不命中 次。
C.
D. 能存下整个数组,只存在冷不命中,不命中率为
6.6 综合:高速缓存对程序性能的影响
练习题 6.21
由图可知, 峰值为 ,每秒读 次,每秒周期数 ,得
第 7 章 链接
7.5 符号和符号表
练习题 7.1
是 | 外部 | m.c |
.data |
|
是 | 全局 | swap.c |
.data |
|
是 | 全局 | swap.c |
COMMON |
|
是 | 全局 | swap.c |
.text |
|
否 | -- |
-- |
-- |
7.6 符号解析
练习题 7.2
A.
(a) -> DEF(main.1)
(b) -> DEF(main.1)
B.
a -> DEF(错误)
(b) -> DEF(错误)
C.
(a) -> DEF(x.2)
(b) -> DEF(x.2)
练习题 7.3
A.
1 | gcc p.o libx.a |
B.
1 | gcc p.o lilbx.a liby.a |
C.
1 | gcc p.o libx.a liby.a libx.a |
练习题 7.4
A. 0x4004e8
B. 0x5
练习题 7.5
refaddr = ADDR(.text) + r.offset = 0x4004da
*refptr = (unsigned)ADDR(swap) + r.addend - refaddr = 0x400e8 - 4 - 0x4004da = 0xa
重定位的值为 4004d9 e8 0a 00 00 00 callq 4004e8 <swap>
第 8 章 异常控制流
8.2 进程
练习题 8.1
是 | |
否 | |
是 |
8.4 进程控制
练习题 8.2
A
p1: x = 2
p1 x = 1
B
p2: x = 0
练习题 8.3
bacc
或 abcc
或 acbc
练习题 8.4
A. 行
B.
设子进程id
为123
1 | Hello |
练习题 8.5
1 |
|
练习题 8.6
1 |
|
练习题 8.7
1 |
|
练习题8.8
1 | 213 |
第 9 章 虚拟内存
9.2 地址空间
练习题 9.1
虚拟地址位数 | 虚拟地址数 | 最大可能虚拟地址数 |
---|---|---|
9.3 虚拟内存作为缓存的工具
练习题 9.2
PTE数量 | ||
---|---|---|
16 | ||
32 | ||
9.6 地址翻译
练习题 9.3
位数 | 位数 | 位数 | 位数 | |
---|---|---|---|---|
练习题 9.4
A.
1 | 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |
B.
参数 | 值 |
---|---|
VPN | 0xf |
0X03 |
|
0X03 |
|
是 | |
0x0D |
|
0x357 |
C
1 | 11 10 9 8 7 6 5 4 3 2 1 0 |
D
参数 | 值 |
---|---|
0x11 |
|
0x5 |
|
0xD |
|
是 | |
0x1D |
9.8 内存映射
练习题 9.5
附录
x86寄存器对照表
63 31 15 7 %rax
%eax
%ax
%al
返回值 %rbx
%ebx
%bx
%bl
被调用者保存 %rcx
%ecx
%cx
%cl
第4个参数 %rdx
%edx
%dx
%dl
第3个参数 %rsi
%esi
%si
%sil
第2个参数 %rdi
%edi
%di
%dil
第1个参数 %rbp
%ebp
%bp
%bpl
被调用者保存 %rsp
%esp
%sp
%spl
栈指针 %r8
%r8d
%r8w
%r8b
第5个参数 %r9
%r9d
%r9w
%r9b
第6个参数 %r10
%r10d
%r10w
%r10b
调用者保存 %r11
%r11d
%r11w
%r11b
调用者保存 %r12
%r12d
%r12w
%r12b
被调用者保存 %r13
%r13d
%r13w
%r13b
被调用者保存 %r1
4%r14d
%r14w
%r14b
被调用者保存 %r15
%r15d
%r15w
%r15b
被调用者保存
二进制、十进制、十六进制对照表
二进制 十进制 十六进制 二进制 十进制 十六进制 0000 0 0 1000 8 8 0001 1 1 1001 9 9 0010 2 2 1010 10 A 0011 3 3 1011 11 B 0100 4 4 1100 12 C 0101 5 5 1101 13 D 0110 6 6 1110 14 E 0111 7 7 1111 15 F