Как устанавливается нулевой флаг в этом коде x86? - PullRequest
0 голосов
/ 11 февраля 2020

Сегодня у нас был cra sh, вызванный арифметическим c исключением в инструкции idiv в следующей сборке x86.

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 понять, в чем проблема? Нужна ли дополнительная информация?

1 Ответ

2 голосов
/ 11 февраля 2020

И этот дамп регистров имеет место до idiv (или после того, как GDB перехватывает SIGFPE, что должно быть то же самое)?

У вас это задом наперед: ZF = 1 означает, что условие "равно" правда . (Так что меньше или равно setle тоже верно). Так что setle cl должно дать вам 1.

С R10 = 1, R10D = 1 также. R10D & R10D != 0 поэтому ZF должен быть очищен. Таким образом, r10d равно НЕ <= 0, поэтому <code>setle помещает 0 в CL, и вы получаете #DE исключение деления.

С этим исходным кодом NASM:

mov    r10d, 1
xor    ecx,ecx
mov    eax, 0x64
test   r10d,r10d
setle  cl
cdq    
idiv   ecx

Встроенный в Linux stati c исполняемый файл с nasm -felf64 foo.asm && ld foo.o -o foo (точка входа по умолчанию находится в верхней части раздела .text), я запустил его в GDB (потому что это было быстрее, чем продумывать все детали, и я хотел посмотреть, были ли EFLAGS изменены ошибочным idiv).

Используйте команду GDB starti, чтобы начать сверху, и пошагово. (С layout reg).

Прямо перед idiv, я получаю EFLAGS = [ IF ], ecx = 0. r10d = 1).

Как и ожидалось, R10D> 0 (не <= 0) приводит к ECX = 0. </strong>

После попытки пройти мимо idiv или использования continue, EFLAGS = [ RF IF ]. Так что ваш дамп реестра GDB не имеет смысла, если только другой ЦП или ОС не может сделать что-то другое с FLAGS в случае ошибки.

...