在x86汇编中,如何在不进行比较的情况下设置零标志位(ZF)?

9
我有一段(x86)汇编代码,我正在试图弄清楚它的作用。
...
 6:     81 ec 00 01 00 00       sub    $0x100, %esp
 c:     31 c9                   xor    %ecx  , %ecx
 e:     88 0c 0c                mov    %cl   , (%esp, %ecx, 1)
11:     fe c1                   inc    %cl
13:     75 f9                   jne    0xe
....

看起来它会循环直到"JNE"评估为false,即零标志= 0。(可能将数字1、2、3...放入堆栈中??)

根据我对汇编的短暂调查(我是新手),似乎通过执行比较操作(CMP)设置零标志,但我没有看到比较操作。

那么,在什么条件下它会跳出这个循环呢?

4个回答

12

inc 操作会在增加后将cl的值与零比较,如果相等则设置ZF标志。你的循环代码如下:

sub    $0x100, %esp            // unsigned char array[256];
xor    %ecx  , %ecx            // unsigned char cl = 0;
mov    %cl   , (%esp, %ecx, 1) // e: array[cl] = cl;
inc    %cl                     //    cl += 1;
jne    0xe                     //    if (cl != 0) goto e;

cl 从255递增并循环回到0时,循环终止并设置ZF标志。


除了 mov %cl, (%esp, %ecx, 1),我认为我都理解了。用英语来说,我会说“将 CX 的低8位(CL)移动到 ESP+ECX地址的RAM中”,这很有道理,但是第三个操作数的 1 是什么意思?这真的是 array[cl + 1] = cl(堆栈溢出?)还是 array[cl] = cl + 1?也许我错过了x86汇编的一些微妙之处,但我很好奇。 - mpontillo
3
数字 1 实际上是一个用于缩放偏移量的尺寸。因此,它实际上是表示数组的大小,即 array[cl * 1] = cl。 - Stephen Canon
1
@Mike:请注意,在英特尔语法中只是 mov [esp+ecx], cl - GreyCat
2
@GreyCat,严谨地说,[esp+1*ecx](特别是没有位移,而不是disp8=0或disp32=0),尽管在这种情况下并不真的存在歧义,因为esp不能用作索引寄存器。 - David X

9

算术指令如add、sub、inc、dec、sar、sal,以及位运算如test、shl、shr、or、and、xor、neg等,都会修改ZF标志位。


非常感谢提供完整的列表,这将非常有用。你是从哪个参考文献中得到这些信息的,还是你自己就知道呢? - Robert
我知道这些指令,但我不得不在英特尔手册/谷歌上查找具体的影响。我不知道有哪些指令会影响ZF。 - newgre

2

像inc和dec这样的数学运算也可以设置零标志。


1

或者,作为入门,将标志位保存到堆栈上 [push],从堆栈中获取寄存器,使用算术或运算符与寄存器上的所需位进行操作,将寄存器推入堆栈并弹出标志位。

就像这样。

pushf
pop ax
or ax, 0x100 [this will set trap flag, you can get the value for any flag or flags you want]
push ax
popf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接