克服86 IDIV #DE例外 [英] Overcoming the x86 idiv #DE exception

查看:211
本文介绍了克服86 IDIV #DE例外的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

回复:x86汇编语言 -

Re: x86 assembly language -

我有3个32位有符号数:N1,N2和N3

I have three 32-bit signed numbers: n1, n2, and n3.

我想通过N2为IMUL N1得到一个64位有符号结果。

I want to imul n1 by n2 to get a 64-bit signed result.

然后我想通过N3到IDIV了64位的结果。

I then want to idiv that 64-bit result by n3.

的问题是,如果在64位带符号的结果是足够大和/或如果n3为足够小,溢出将导致和IDIV将抛出#DE异常。

The problem is that if the 64-bit signed result is large enough and/or if n3 is small enough, an overflow will result and idiv will throw a #DE exception.

如果IDIV简单的设置上溢#DE,我可以检查,以确认
((N1 * N2)/ N3)* N3 +((N1 * N2)MOD N3)=(N * N2)。如果没有,溢出会发生,我可以照此办理。

If idiv simply set #DE on overflow, I could check to confirm that ((n1 * n2) / n3) * n3 + ((n1 * n2) mod n3) = (n1 * n2). If not, overflow would have occurred and I could proceed accordingly.

但#DE不与别人玩好。当它的提出,它报告程序已停止工作,然后踢你出去。

But #DE does not play nice with others. When it's raised, it reports "Program has stopped working" and then kicks you out.

所以,我要么需要找到pre-检查的IDIV是否会导致溢出我司之前,还是我需要做一个尝试的汇编语言等效...抓住。一些方法

So i either need to find some way of pre-checking whether an idiv will cause an overflow before I do the division, or I need to do the equivalent of a try ... catch in assembly language.

我搜索互联网(包括在这里),找到这个一般很少;并没有什么特别有用。

I've searched the internet (including here) and find very little on this in general; and nothing that is particularly useful.

我试过内联code A C ++里面试试... CATCH无济于事 - 它仍然报告程序已停止工作,然后你踢出

I've tried inlining the code inside a c++ try ... catch to no avail - it still reports "Program has stopped working" and then kicks you out.

例如,与两个支持文件:

For example, with the two supporting files:

// TC.h
// Version 1.0.0
// MDJ 2016/05/06

extern "C" int q;
extern "C" int m;

// TC.s
// Version 1.0.0
// MDJ 2016/05/06

    .globl _q
    .globl _m

    .bss
    .align 4
_q:
   .space 4

_m:
    .space 4

这个文件运行完成,并产生正确的结果:

this file runs to completion and produces the correct results:

// TryCatch.cpp
// Version 1.0.0
// MDJ 2016/05/06

#include <iostream>
#include "TC.h"

using namespace std;

int main() {

    cout << endl;

    try {

        # AT&T syntax
        asm(
            "movl       $34,    %eax\n\t"
            "movl       $48,    %edx\n\t"
            "imull  %edx\n\t"
            "movl       $13,    %ecx\n\t"
            "idivl  %ecx\n\t"
            "movl       %eax,   _q\n\t"
            "movl       %edx,   _m\n\t"
        );
    }
    catch(int e) {
        cout << "Caught." << endl;
    }

    cout << "Reached the End." << endl;
    cout << "q = " << q << endl;
    cout << "m = " << m << endl;
    cout << endl;

    return 0;
}

但是,如果我改变N1,N2和N3是这样的:

But, if I change n1, n2, and n3 like this:

// TryCatch.cpp
// Version 1.0.0
// MDJ 2016/05/06

#include <iostream>
#include "TC.h"

using namespace std;

int main() {

    cout << endl;

    try {

        # AT&T syntax
        asm(
            "movl       $234567890, %eax\n\t"
            "movl       $123456789, %edx\n\t"
            "imull  %edx\n\t"
            "movl       $3, %ecx\n\t"
            "idivl  %ecx\n\t"
            "movl       %eax,   _q\n\t"
            "movl       %edx,   _m\n\t"
        );
    }
    catch(int e) {
        cout << "Caught." << endl;
    }

    cout << "Reached the End." << endl;
    cout << "q = " << q << endl;
    cout << "m = " << m << endl;
    cout << endl;

    return 0;
}

抓不接住溢出和系统,而不是报告程序已停止工作,然后踢你出去。

the "catch" doesn't catch the overflow and the system instead reports "Program has stopped working" and then kicks you out.

任何帮助将是AP preciated。

Any help would be appreciated.

推荐答案

我突然发生,我认为我完全是在错误的轨道(并且作为一种模式railroader,这是一个真正的滔天罪行)双关语意上:-)。

It suddenly occurred to me that I'm completely on the wrong track (and as a model railroader, that's a truly heinous crime ) Pun intended :-).

不过,说真的,我一直要对这个硬盘的方式。

But, really, I've been going about this the hard way.

相反,我应该采取简单的方法:我要回到我的1950年的文法学校和我的长师第一历险

Instead, I should take the easy way: I should go back to my 1950's grammar school and my first adventures with long division.

而不是令人费解的EDX:EAX被分为ECX,让我们觉得两位数(无符号)数量由一个数字(符号)个数除的

Instead of puzzling over EDX:EAX being divided by ECX, let's think of a two digit (unsigned) number being divided by a one digit (unsigned) number.

现在,在两位数字是被除数,它有一个个位数字和十位数字。所以它可在0至99之间变化。

Now, the two-digit number is the dividend, and it has a ones digit and a tens digit. So it can vary between 0 and 99.

和,一个数字是除数,并且它只有一个个位数字。因此,可以1和9之间变化(因为被零除是不允许的)。

And, the one-digit number is the divisor, and it has only a ones digit. Thus, it can vary between 1 and 9 (because division by zero is not allowed).

考虑,例如,77除以2:

Consider, for example, 77 divided by 2:

                            3 8
                           _____
                        2 | 7 7
                            6
                            _
                            1 7
                            1 6
                            ___
                              1

所以,其结果是:商为38,余数为1

So, the result is: the quotient is 38 and the remainder is 1.

但是,在这里,像分红,我们允许商也有两个数字:一个十位数和个位数。如果我们不是限制商数只具有个位数会发生什么。

But, here, like with the dividend, we're allowing the quotient to also have two digits: a tens digit and a ones digit. What would happen if we instead limit the quotient to having only the ones digit.

然后,我们可以调用任何分裂,从而导致具有比在十位数场零任何数字以外的商数,溢出!

Then we could call any division, which results in the quotient having any numeral other than zero in the tens digit field, AN OVERFLOW !!!

不过,那么,什么是产生这种溢出所需要的条件:它是小于或等于被除数的十位数字任意因数!

But, then, what is the condition required to produce such an overflow: ANY DIVISOR WHICH IS SMALLER THAN OR EQUAL TO THE NUMERAL IN THE TENS DIGIT OF THE DIVIDEND !!!

类似地,在EDX的分工:由EAX ECX,就会发生溢出,如果ECX&LT; = EDX!

Analogously, in the division of EDX:EAX by ECX, an overflow will occur if ECX <= EDX !!!

这就是我们这样溢出简单的测试:

And that is thus our simple test for overflow:

                        ECX <= EDX

这是无符号划分工作。

pre-检查符号除法溢出是显著更复杂。我认为这会工作,但我仍在测试。

Pre-checking for signed divide overflow is significantly more complicated. I think this will work, but I'm still testing.

在EDX 64位有符号开始分红:EAX与ECX中的32位有符号除数。然后:

Begin with the 64-bit signed dividend in EDX:EAX and with the 32-bit signed divisor in ECX. Then:

  # Temporarily save the dividend
  movl  %edx, _dividendHigh                     # Most-significant 32b
  movl  %eax, _dividendLow                      # Least-significant 32b

  # Check the divisor for zero
  testl %ecx, %ecx                              # Is divisor = 0 ?
  jz    _DivideByZero                           # Go if Yes

  # Check the divisor for +/- 1
  cmpl  $1, %ecx
  je    _dChkA                                  # Go if divisor =  1
  cmpl  $-1,    %ecx
  je    _dChkA                                  # Go if divisor = -1
  jmp   _dChkC                                  # Else continue

_dChkA:
  # If dividendHigh < -1 or > 0 and divisor = +/- 1
  #   then overflow will occur.
  cmpl  $-1,        %edx
  jl    _DivideOverflow                         # Go if divHigh < -1
  cmpl  $0,     %edx
  jg    _DivideOverflow                         # Go if divHigh >    0

  # If dividendHigh = -1 and bit 31 of dividendLow = 0
  #   and divisor = +/- 1 then overflow will occur.
  cmpl  $-1,    %edx
  jne   _dChkB                                  # Go if divHigh <>  -1
  bt    $31,    %eax
  jnc   _DivideOverflow                         # Go if divLow b31 = 0

_dChkB:
  # If dividendHigh = 0 and bit 31 of dividendLow = 1
  #   and divisor = +/- 1 then overflow will occur.
  cmpl  $0, %edx
  jne   _dChkC                                  # Go if divHigh <>   0
  bt    $31,    %eax
  jc    _DivideOverflow                         # Go if divLow b31 = 1

  # Check for non-unary overflow
  #   Overflow will occur if the 
  #   most-significant 33b can be
  #   divided by the divisor. NOTE:
  #   that's 33 bits, not 32, 
  #   because all numbers are signed.

  # Do dividend shift and manual sign extension
  # Check bit 63 to determine if dividend is positive or negative
_dChkC: 
  bt    $31,    %edx
  jc    _dChkD                                  # Go if negative

  # Do the 64-bit shift                         # Positive
  # First, shift the Least-significant
  #   32b left 1 bit (bit 32 --> CF).
  shll  $1, %eax

  # Then, rotate the Most-significant
  #   32b left, through the carry, 1 bit
  #   (CF --> bit 1 then bit 32 --> CF).
  rcll  $1, %edx

  # Move it to %eax and manually positive-sign extend it
  movl  %edx,   %eax
  jmp       _dChkE

_dChkD:                                             # Negative  
  # Do the 64-bit shift                                     
  # First, shift the Least-significant
  #   32b left 1 bit (bit 32 --> CF).
  shll  $1, %eax

  # Then, rotate the Most-significant
  #   32b left, through the carry, 1 bit
  #   (CF --> bit 1 then bit 32 --> CF).
  rcll  $1, %edx

  # Move it to %eax and manually negative-sign extend it
  movl  %edx,   %eax
  movl  $-1,    %edx

  # Do the Test Divide of the 
  #   Most-Significant 33b
_dChkE:
  idivl %ecx                                    # EDX:EAX / ECX
                                                #   EAX = test quotient
                                                #   EDX = test remainder
  testl %eax,   %eax
  jnz       _DivideOverflow                     # Go if Quotient <> 0

  # Get the full dividend
  movl  _dividendHigh,  %edx                    # Most-significant 32b
  movl  _dividendLow,   %eax                    # Least-significant 32b

  # Perform the 64b by 32b division
  idivl ecx                                     #   EDX:EAX / ECX
                                                #     EAX = quotient
                                                #     EDX = remainder

这篇关于克服86 IDIV #DE例外的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆