【问题标题】:How is the zero flag set in this x86 code?这个 x86 代码中的零标志是如何设置的?
【发布时间】:2020-02-11 13:49:45
【问题描述】:

我们今天遇到了崩溃,原因是以下 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 之后)?是的,R10 = 1, R10D & R10D != 0 所以 ZF 应该被清除。因此r10dNOT setle 在CL 中放置了0
  • 此代码设计为在 r10 > 0 时崩溃。因此,它确实做到了这一点也就不足为奇了。
  • 我后来发现我太兴奋了查看程序集并错过了代码中明显的愚蠢错误。希望下次我能记住这一点......

标签: assembly x86-64 divide-by-zero


【解决方案1】:

而且这个寄存器转储来自idiv 之前(或者在 GDB 捕获应该是同一件事的 SIGFPE 之后)?

反过来说:ZF=1 表示“等于”条件为 true。 (所以小于或等于setle 也是正确的)。所以setle cl 应该给你一个1

R10 = 1,R10D = 1。 R10D & R10D != 0 所以 ZF 应该被清除。因此r10dNOT 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(入口点默认位于 .text 部分的顶部)内置到 Linux 静态可执行文件中,我在 GDB 下运行它(因为这比考虑所有细节要快,并且我想看看 EFLAGS 是否被错误的 idiv 改变了)。

使用 GDB 的 starti 命令从顶部开始,单步执行。 (与layout reg)。

就在idiv 之前,我得到EFLAGS = [ IF ]ecx = 0(与r10d = 1)。

正如预期的那样,R10D > 0(不是

在尝试跳过idiv,或使用continueEFLAGS = [ RF IF ] 之后。因此,您的 GDB 寄存器转储没有意义,除非不同的 CPU 或操作系统可以在故障上使用 FLAGS 执行不同的操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多