这个 x86 代码中的零标志是如何设置的?
How is the zero flag set in this x86 code?
由于以下 x86 汇编中的 idiv 指令中的算术异常,我们今天遇到了崩溃。
mov r10d,DWORD PTR [rbp+0x70]
xor ecx,ecx
mov eax,r15d
test r10d,r10d
setle cl
cdq
idiv ecx
这里是gdb中所有寄存器的值:
rax 0x64 100
rbx 0xaebc30 11451440
rcx 0x0 0
rdx 0x0 0
rsi 0x1 1
rdi 0xaebc88 11451528
rbp 0x7fa56809b840 0x7fa56809b840
rsp 0x7fa56effc080 0x7fa56effc080
r8 0x12 18
r9 0x100016a0000a72e 72059148816131886
r10 0x1 1
r11 0x0 0
r12 0x9e2bb8 10365880
r13 0x0 0
r14 0xaebc80 11451520
r15 0x64 100
rip 0x495ebb 0x495ebb
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
由于设置了零标志,setle cl
将 0 写入 ecx,这导致被零除。我不明白的是零标志是如何设置的。 r10 的值为 1,因此据我所知 test r10d,r10d
应该取消设置它。 cdq
似乎没有修改它,所以我不确定这里发生了什么。
有更多 x86 经验的人能理解问题出在哪里吗?需要更多信息吗?
这个寄存器转储是在 idiv
之前(或者在 GDB 捕捉到 SIGFPE 之后,这应该是同一件事)?
倒过来:ZF=1 表示 "equals" 条件为 true。 (所以小于或等于 setle
也是正确的)。所以 setle cl
应该给你 1
.
R10 = 1 时,R10D = 1。 R10D & R10D != 0
所以 ZF 应该 被清除。因此 r10d
是 NOT <= 0,所以 setle
在 CL 中放置了一个 0
并且你确实得到了一个 #DE
除法异常。
有了这个NASM源代码:
mov r10d, 1
xor ecx,ecx
mov eax, 0x64
test r10d,r10d
setle cl
cdq
idiv ecx
使用 nasm -felf64 foo.asm
&& ld foo.o -o foo
内置到 Linux 静态可执行文件中(入口点默认位于 .text 部分的顶部),我 运行 它位于GDB(因为这比考虑所有细节要快,我想看看 EFLAGS 是否被错误的 idiv 更改了)。
使用GDB的starti
命令从头开始,单步执行。 (有 layout reg
)。
在 idiv
之前,我得到 EFLAGS = [ IF ]
、ecx = 0
。(r10d = 1
)。
正如预期的那样,R10D > 0(不是 <= 0)导致 ECX = 0。
尝试越过 idiv
或使用 continue
、EFLAGS = [ RF IF ]
后。所以你的 GDB 寄存器转储没有意义,除非不同的 CPU 或 OS 可以在错误时用 FLAGS 做一些不同的事情。
由于以下 x86 汇编中的 idiv 指令中的算术异常,我们今天遇到了崩溃。
mov r10d,DWORD PTR [rbp+0x70]
xor ecx,ecx
mov eax,r15d
test r10d,r10d
setle cl
cdq
idiv ecx
这里是gdb中所有寄存器的值:
rax 0x64 100
rbx 0xaebc30 11451440
rcx 0x0 0
rdx 0x0 0
rsi 0x1 1
rdi 0xaebc88 11451528
rbp 0x7fa56809b840 0x7fa56809b840
rsp 0x7fa56effc080 0x7fa56effc080
r8 0x12 18
r9 0x100016a0000a72e 72059148816131886
r10 0x1 1
r11 0x0 0
r12 0x9e2bb8 10365880
r13 0x0 0
r14 0xaebc80 11451520
r15 0x64 100
rip 0x495ebb 0x495ebb
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
由于设置了零标志,setle cl
将 0 写入 ecx,这导致被零除。我不明白的是零标志是如何设置的。 r10 的值为 1,因此据我所知 test r10d,r10d
应该取消设置它。 cdq
似乎没有修改它,所以我不确定这里发生了什么。
有更多 x86 经验的人能理解问题出在哪里吗?需要更多信息吗?
这个寄存器转储是在 idiv
之前(或者在 GDB 捕捉到 SIGFPE 之后,这应该是同一件事)?
倒过来:ZF=1 表示 "equals" 条件为 true。 (所以小于或等于 setle
也是正确的)。所以 setle cl
应该给你 1
.
R10 = 1 时,R10D = 1。 R10D & R10D != 0
所以 ZF 应该 被清除。因此 r10d
是 NOT <= 0,所以 setle
在 CL 中放置了一个 0
并且你确实得到了一个 #DE
除法异常。
有了这个NASM源代码:
mov r10d, 1
xor ecx,ecx
mov eax, 0x64
test r10d,r10d
setle cl
cdq
idiv ecx
使用 nasm -felf64 foo.asm
&& ld foo.o -o foo
内置到 Linux 静态可执行文件中(入口点默认位于 .text 部分的顶部),我 运行 它位于GDB(因为这比考虑所有细节要快,我想看看 EFLAGS 是否被错误的 idiv 更改了)。
使用GDB的starti
命令从头开始,单步执行。 (有 layout reg
)。
在 idiv
之前,我得到 EFLAGS = [ IF ]
、ecx = 0
。(r10d = 1
)。
正如预期的那样,R10D > 0(不是 <= 0)导致 ECX = 0。
尝试越过 idiv
或使用 continue
、EFLAGS = [ RF IF ]
后。所以你的 GDB 寄存器转储没有意义,除非不同的 CPU 或 OS 可以在错误时用 FLAGS 做一些不同的事情。