常见x86汇编指令解释
例题:已知 f(n)=n! =nX(n-1)X··X2X1,计算 f(n)的 C 语言函数 f(n) 的源程序(圈住的地方)及其在 32 位计算机 M 上的部分机器级代码如下:
其中,机器级代码行包括行号、虚拟地址、机器指令和汇编指令,计算机 M 按字节编址int 型数据占 32 位。请回答下列问题:
- (1) 计算 f(10)需要调用函数 f1 多少次? 执行哪条指会递归调用 f1?
- (2)上述代码中,哪条指令是条件转移指令? 哪几条指令一定会使程序跳转执行?
- (3) 根据第 16 行 call 指令,第 17 行指的虚拟地址应是多少? 已知第 16 行 call 指今采用相对寻址方式,该指今中的偏移量应是多少(给出计算过程)? 已知第 16 行 call 指的后4字节为偏移量,M 采用大端还是小端方式?
- (4) f(13)=6227020 800,但 f1(13)的返回值为 1932053 504,为什么两者不相等? 要使 f1(13)能返回正确的结果,应如何修改 f1 源程序?
- (5) 第19 行 imul eax,ecx 表示有符号数乘法,乘数为 R[eax]和 R[ecx],当乘法器输出的高、低 32 位乘积之间满足什么条件时,溢出标志 OF=1? 要使 CPU 在发生溢出时转异常处理编译器应在 imul 指令后加一条什么指令?
【分析】由题中可以看出是计算n的阶乘的一个C语言代码的机器代码。只有四个代码操作,就是定义函数f1,判断n是否小于1,还有进行f1的递归操作,最后返回1.
【解答】
1.f1(10)结合题意可以知道是10 的阶乘,而且c语言代码是通过递归进行的,故需要调用f1函数10次。而查阅汇编表可以知道调用函数是call指令,故是第16条指令会递归调用f1.
2.根据汇编指令表可以知道,条件跳转指令为jle指令,故机器代码中第12行的jle指令是条件转移指令,jle f1+35H即如果n<=1时,就跳转到地址为00401035H。
第16行的call指令为函数调用指令,第20行的jmp指令为无条件转移指令,第30行的ret指令为子程序的返回指令,故这三条指令一定会使得程序跳转执行。
3.计算机M是按字节编址的,故第16行call指令的虚拟地址为0040 1025H,长度为E8 D6 FF FF FF占了五个字节,故第17行的虚拟地址为 0040 1025H+5=0040 102AH;
采用相对寻址,则 偏移量=目标地址 - (PC) = 0040 1000H - 0040 102AH=FFFF FFD6H。
根据第16行的call指令的偏移量字段为D6 FF FF FF,可以确定M采用小端方式。
4.f(13)=6227020800超出了int型32位表示的最大范围,因此返回值是发生了溢出的错误结果。
为了使得f1(13)能够表示正确的结果,可以将返回类型改为double(或者long long,long double,float)类型。
5.若32乘积的高33位为非全0或者非全1,则OF=1。(第33位为乘积的符号位,如果第33位以后出现不一样的二进制位,则表示32位不够表示乘积,因此溢出。)
要想发生溢出时转为异常处理,常见的内部异常指令为“trap指令”,因此要在imul指令后加入一条“溢出自陷指令”,使得CPU自动查询溢出标志OF,当OF=1时调出“溢出异常处理程序”。