指令系统(2017统考真题)
指令系统(2017统考真题)
原始 C 语言函数为
int f1(unsigned n){
int sum = 1, power = 1;
for (unsigned i = 0; i < n-1; i++){
power *= 2;
sum += power;
}
return sum;
}
该函数计算的是一个几何级数的和,其数学表达式为
f ( n ) = 1 + 2 + 2 2 + ⋯ + 2 n − 1 = 2 n − 1. f(n) = 1 + 2 + 2^2 + \cdots + 2^{n-1} = 2^n - 1. f(n)=1+2+22+⋯+2n−1=2n−1.
题目的要求是:将函数中所有的 int
换成 float
得到函数 f2(利用浮点运算计算 f(n)),同时给出与 f1 相关的机器级代码,提出下面四个问题,从汇编指令、机器代码占用、运算和浮点实现等角度考察对底层机制的理解。
附上的部分机器代码如下(每行包括行号、虚拟地址、机器指令及对应汇编指令):
int f1(unsigned n)
1 00401020 55 push ebp
... ...
for(unsigned i=0;i<n-1;i++)
... ...
20 0040105E 39 4D F4 cmp dword ptr [ebp-0Ch], ecx
... ...
power *= 2;
... ...
23 00401066 D1 E2 shl edx,1
... ...
return sum;
35 0040107F C3 ret
下面依次对每个问题做详细分析和解释。
问题 1:机器 M 是 RISC 还是 CISC?为什么?
解答与分析:
- 题目中给出的指令包括
push ebp
、cmp dword ptr [ebp-0Ch], ecx
、shl edx,1
和ret
等。 - 观察这些指令可以发现:
- 指令长度不固定(例如
push ebp
占 1 个字节,而cmp
指令可能占 3 个字节)。 - 存在复杂的寻址方式,如
dword ptr [ebp-0Ch]
表示基址+偏移的内存访问。
- 指令长度不固定(例如
- 这些都是典型的**CISC(复杂指令集计算机)**特点,而非 RISC(精简指令集计算机)的特征。
- RISC 通常要求固定指令长度和简单的寻址模式,且大多数操作要求在寄存器间进行。
- 而 x86 这类采用可变长度和丰富寻址方式的体系正是 CISC。
答案:
机器 M 属于 CISC 架构,因为它使用了可变长度(例如 push
、cmp
、shl
等)和复杂寻址模式,这些都是 CISC 的典型特征。
问题 2:f1 的机器指令代码共占多少个字节?要求给出计算过程。
解答与分析:
从给出的机器代码中我们知道:
- 第一条指令出现在虚拟地址
00401020 \mathtt{00401020} 00401020 - 最后一条指令(
ret
)出现在虚拟地址
0040107 F \mathtt{0040107F} 0040107F
计算连续代码区域所占的字节数时,可以按照下式计算(包含首尾地址上的所有字节):
总字节数 = ( 最后地址 − 首地址 ) + 最后一条指令的字节数 \text{总字节数} = (\text{最后地址} - \text{首地址}) + \text{最后一条指令的字节数} 总字节数=(最后地址−首地址)+最后一条指令的字节数
其中:
-
00401020
到0040107F
的地址差为
0040107 F − 00401020 = 0 x 7 F − 0 x 20 = 0 x 5 F ( 十六进制 ) \mathtt{0040107F} - \mathtt{00401020} = 0x7F - 0x20 = 0x5F \quad (\text{十六进制}) 0040107F−00401020=0x7F−0x20=0x5F(十六进制) -
但由于地址是连续且包含首尾,应再加 1 字节(而每个地址对应 1 个字节)。
-
因此,总字节数为
0 x 5 F + 1 = 0 x 60 = 96 字节 . 0x5F + 1 = 0x60 = 96 \text{ 字节}. 0x5F+1=0x60=96 字节.
答案:
f1 的机器指令代码占 96 字节,其计算过程为
总字节数
=
(
0040107
F
−
00401020
)
+
1
=
0
x
5
F
+
1
=
0
x
60
=
96
字节
.
\text{总字节数} = (0040107F - 00401020) + 1 = 0x5F + 1 = 0x60 = 96 \text{ 字节}.
总字节数=(0040107F−00401020)+1=0x5F+1=0x60=96 字节.
问题 3:关于第 20 行 cmp
指令
“cmp 通过 i 减小 1 实现对 i 与 n-1 的比较。在执行 f1(0) 的过程中,当 i = 0 时,cmp 指令执行后进位置/借位置标志 CF 的内容是什么?要求给出计算过程。”
解答与分析:
-
根据编译器生成的代码,变量
i
存于内存地址 [ebp-0Ch],而寄存器ecx
中传递的值为n-1
。 -
注意:由于传入参数
n
为无符号整数,当n = 0
时,
n − 1 = 0 − 1 ≡ 0 x F F F F F F F F ( 以 32 位无符号数理解 ) n - 1 = 0 - 1 \equiv 0xFFFFFFFF \quad (\text{以 32 位无符号数理解}) n−1=0−1≡0xFFFFFFFF(以 32 位无符号数理解)
在循环初始时,i
被初始化为 0,所以 cmp 指令执行时是:
cmp [ e b p − 0 C h ] , e c x ⟹ 比较 0 和 0 x F F F F F F F F . \text{cmp} \; [\mathtt{ebp-0Ch}], \; \mathtt{ecx} \quad\Longrightarrow\quad \text{比较 } 0 \text{ 和 } 0xFFFFFFFF. cmp[ebp−0Ch],ecx⟹比较 0 和 0xFFFFFFFF.
-
cmp
指令内部执行的运算相当于
0 − 0 x F F F F F F F F . 0 - 0xFFFFFFFF. 0−0xFFFFFFFF. -
在 无符号运算中,如果被减数小于减数,则产生借位。
- 由于 0 < 0 x F F F F F F F F 0 < 0xFFFFFFFF 0<0xFFFFFFFF,因此当执行 0 − 0 x F F F F F F F F 0 - 0xFFFFFFFF 0−0xFFFFFFFF 时,会造成借位,进而 CF(进位标志)被置为 1。
(顺便说明:尽管模
2
32
2^{32}
232 的减法结果为
0
x
100000000
−
0
x
F
F
F
F
F
F
F
F
=
1
,
0x100000000 - 0xFFFFFFFF = 1,
0x100000000−0xFFFFFFFF=1,
但关键是对无符号减法而言,CF 用于表示是否产生借位。)
答案:
对于 f1(0)
,当 i = 0
时,执行
0
−
0
x
F
F
F
F
F
F
F
F
0 - 0xFFFFFFFF
0−0xFFFFFFFF
导致产生借位,故 cmp 指令执行后,CF = 1。
问题 4:关于第 23 行 shl
指令
“第 23 行指令 shl 通过左移操作实现了 power2 的运算,请问在 f2 中能否用 shl 指令实现 power2?为什么?”
解答与分析:
- 在 f1 中,
power
为整数,通过shl edx, 1
实现左移 1 位(即乘以 2)的操作。这在整数的补码表示下是正确且高效的。 - 而在 f2 中,所有的
int
都改成float
,也就是使用浮点数进行运算。 - 浮点数(通常遵循 IEEE 754 标准)的内部表示与整数截然不同:
- 浮点数由符号位、指数和尾数(有效数字)组成,
- 并非连续的数值二进制序列,直接对其进行位移操作将破坏其格式,不会实现数学上乘 2 的效果。
- 因此,在 f2 中,若使用整数指令
shl
对浮点数的二进制表示进行左移,其结果既不能正确计算 p o w e r × 2 power \times 2 power×2,也不会遵循浮点数运算规则。
答案:
在 f2 中无法使用 shl
指令实现 power*2
运算。因为浮点数采用 IEEE 754 格式,其二进制表示不适合直接位移运算。正确的做法应当使用浮点乘法指令(例如 fmul
或 SIMD 指令)以保证乘法运算的正确性。
涉及的主要知识点
-
整数与浮点数表示及运算
- 补码表示:
负数的表示方法:先逐位取反,再加 1。补码使得 N + ( − N ) ≡ 0 ( mod 2 n ) N + (-N) \equiv 0 \;(\text{mod }2^n) N+(−N)≡0(mod 2n)。 - 浮点数表示:
遵循 IEEE 754 标准,由符号位、指数位和尾数位构成,不适用于直接的位移操作。
- 补码表示:
-
CISC 与 RISC 架构
- CISC 特点:
可变长度指令、复杂寻址模式(如基址加偏移)、较多的操作数种类。 - RISC 特点:
固定长度指令、简化的寻址模式,要求大部分算术运算在寄存器中进行。
- CISC 特点:
-
汇编指令及机器级代码分析
- 关键指令:
push
和ret
:函数调用与返回。cmp
指令:通过执行减法(不保存结果)设置标志位,用于实现条件判断。尤其要理解 CF(进位标志)的含义,若无符号减法中被减数小于减数,则 CF 被置 1。shl
指令:左移操作,对于整数左移 1 位等于乘以 2。
- 机器代码空间计算:
根据起始和结束地址,并注意地址包含性来计算总字节数。
- 关键指令:
-
无符号数运算与模 2 n 2^n 2n 算术
- 当对无符号数进行减法时,若结果为负则取模 2 n 2^n 2n 得到对应补码表示,例如 0 − 1 = 2 32 − 1 = 0 x F F F F F F F F 0 - 1 = 2^{32} - 1 = 0xFFFFFFFF 0−1=232−1=0xFFFFFFFF。
-
高层语言到汇编代码的转换
- 理解 C 语言循环、条件比较和算术运算如何转换成汇编指令,并反推各局部变量如何在寄存器或内存中映射。
-
浮点运算的特殊性
- 位运算指令(如
shl
)适用于整数,但浮点数运算需要使用专用的硬件指令以保证正确的数学运算。
- 位运算指令(如