2019-45
已知 f(n) = n! = n×(n-1)×(n-2)×…×2×1,计算 f(n) 的 C 语言函数 f1 的源程序(阴影部分)及其在 32 位计算机 M 上的部分机器级代码如下:
其中,机器级代码行包括行号、虚拟地址、机器指令和汇编指令,计算机M按字节编址,int型数据占32位。请回答下列问题:

(1)计算 f(10) 需要调用函数 f1 多少次?执行哪条指令会递归调用 f1?
(2)上述代码中,哪条指令是条件转移指令?哪几条指令一定会使程序跳转执行?
(3)根据第 16 行的 call 指令,第 17 行指令的虚拟地址应是多少?已知第 16 行的 call 指令采用相对寻址方式,该指令中的偏移量应是多少(给出计算过程)?已知第 16 行的 call 指令的后 4 字节为偏移量,M 是采用大端方式还是采用小端方式?
(4)f(13) = 6227020800,但 f1(13) 的返回值为 1932053504,为什么两者不相等?要使 f1(13) 能返回正确的结果,应如何修改 f1 的源程序?
(5)第 19 行的 imul 指令(带符号整数乘)的功能是 R[eax]←R[eax]×R[ecx],当乘法器输出的高、低 32 位乘积之间满足什么条件时,溢出标志 OF=1? 要使 CPU 在发生溢出时转异常处理,编译器应在 imul 指令后应加一条什么指令?
(1)计算 f(10) 共调用 f1 10 次;第 16 行 call 指令递归调用 f1。
(2)第 12 行 jle 是条件转移指令;第 16 行 call、第 20 行 jmp 和第 30 行 ret 一定使程序跳转。
(3)第 17 行地址为 0040102AH。偏移量为
00401000H-0040102AH=FFFFFFD6H,机器码中的存放顺序为 D6 FF FF FF,因此 M 采用小端方式。
(4)int 型只能表示 [-231,231-1],而 f(13)=6\,227\,020\,800>231-1,因此发生溢出。可将形参、局部变量和返回值改为 double(或足够宽的整数类型)。
(5)若 64 位乘积的高 32 位不是低 32 位的符号扩展,则 OF=1。编译器应在 imul 后加入溢出自陷指令,使 CPU 在 OF=1 时转入溢出异常处理程序。