如何在此x86代码中设置零标志?

问题描述 投票:0回答:1

我们今天由于以下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经验的人可以理解问题所在吗?是否需要更多信息?

assembly x86-64 divide-by-zero
1个回答
0
投票

并且此寄存器转储是从idiv之前(或GDB捕获SIGFPE之后应该是同一件事)?

您向后看:ZF = 1表示“等于”条件为true。 (因此,小于或等于setle也是如此)。因此,setle cl应该给您一个1

[R10 = 1时,R10D = 1。 R10D & R10D != 0,因此清除ZF 应该。因此,r10dNOT <= 0,因此setle0放在CL中,并且您确实获得了#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 ]。因此,除非故障发生时不同的CPU或OS可以对FLAGS做一些不同的事情,否则您的GDB寄存器转储是没有意义的。

© www.soinside.com 2019 - 2024. All rights reserved.