克服 x86 idiv #DE 异常

2023-12-25

回复:x86 汇编语言 -

我有三个 32 位有符号数:n1、n2 和 n3。

我想对 n1 乘以 n2 进行 imul 以获得 64 位带符号的结果。

然后我想将该 64 位结果除以 n3。

问题是,如果 64 位有符号结果足够大和/或 n3 足够小,就会导致溢出,并且 idiv 将引发 #DE 异常。

如果 idiv 只是在溢出时设置 #DE,我可以检查以确认 ((n1 * n2) / n3) * n3 + ((n1 * n2) mod n3) = (n1 * n2)。如果没有,就会发生溢出,我可以相应地继续。

但#DE 与其他人相处并不融洽。当它被提出时,它会报告“程序已停止工作”,然后将您踢出。

因此,我要么需要找到某种方法来在进行除法之前预先检查 idiv 是否会导致溢出,要么需要在汇编语言中执行相当于 try ... catch 的操作。

我搜索过互联网(包括这里),但总体上很少发现这方面的信息;并没有什么特别有用的东西。

我尝试将代码内联到 c++ try ... catch 中,但无济于事 - 它仍然报告“程序已停止工作”,然后将您踢出。

例如,使用两个支持文件:

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

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

and

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

    .globl _q
    .globl _m

    .bss
    .align 4
_q:
   .space 4

_m:
    .space 4

该文件运行完成并产生正确的结果:

// 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:

// 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;
}

“catch”不会捕获溢出,系统会报告“程序已停止工作”,然后将您踢出。

任何帮助,将不胜感激。


我突然意识到我完全走错了路(作为一名模型铁路工人,这真是令人发指的罪行)双关语的意思:-)。

但说实话,我一直在努力解决这个问题。

相反,我应该采取简单的方法:我应该回到 1950 年代的文法学校和我第一次长除法的冒险。

我们不要对 EDX:EAX 除以 ECX 感到困惑,而是考虑将两位数(无符号)数除以一位数(无符号)数。

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

并且,一位数就是除数,并且只有一位数。因此,它可以在 1 到 9 之间变化(因为不允许除以零)。

例如,考虑 77 除以 2:

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

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

但是,在这里,就像被除数一样,我们允许商也有两位数:十位数字和个位数字。如果我们将商限制为只有个位,会发生什么情况。

然后我们可以调用任何除法,这会导致商在十位数字字段中具有除零之外的任何数字,溢出!

但是,那么,产生这种溢出所需的条件是什么:任何小于或等于被除数的十位数字的除数!

类似地,在 EDX:EAX 除以 ECX 时,如果 ECX

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

                        ECX <= EDX

这适用于无符号除法。

预检查有符号除法溢出要复杂得多。我认为这会起作用,但我仍在测试。

从 EDX:EAX 中的 64 位有符号除数开始,从 ECX 中的 32 位有符号除数开始。然后:

  # 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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

克服 x86 idiv #DE 异常 的相关文章

  • 32 位到 64 位内联汇编移植

    我有一段 C 代码 在 GNU Linux 环境下用 g 编译 它加载一个函数指针 它如何执行并不重要 使用一些内联汇编将一些参数推送到堆栈上 然后调用该函数 代码如下 unsigned long stack 1 23 33 43 save
  • 如何捕获 try-with-resource 语句中 close 方法抛出的异常

    我正在读关于try with resourceJava 中的语句可用于指定任意数量的资源 try Resource1 res1 initialize code Resource1 res2 initialize code statement
  • Android SoundPool 堆限制

    我正在使用 SoundPool 加载多个声音剪辑并播放它们 据我所知 它的功能 100 正确 但在 load 调用期间 我的日志中充斥着以下内容 06 09 11 30 26 110 ERROR AudioCache 23363 Heap
  • Clang 编译器 (x86):80 位长双精度

    我正在尝试在 x86 Windows 平台上使用本机 80 位长双精度 海湾合作委员会选项 mlong double 80 https gcc gnu org onlinedocs gcc x86 Options html似乎不适用于 cl
  • 如何将函数内的捕获错误传递给父级

    我有这几行代码示例 想知道下面的逻辑到底如何 try var response child console log why here catch err console log should show this err function c
  • 当前的 x86 架构是否支持非临时加载(来自“正常”内存)?

    我知道有关此主题的多个问题 但是 我没有看到任何明确的答案或任何基准测量 因此 我创建了一个处理两个整数数组的简单程序 第一个数组a非常大 64 MB 第二个数组b很小 无法放入 L1 缓存 程序迭代a并将其元素添加到相应的元素中b在模块化
  • 我应该把 try/catch 和“using”语句放在哪里? [复制]

    这个问题在这里已经有答案了 可能的重复 try catch using 正确的语法 https stackoverflow com questions 4590490 try catch using right syntax 我想try c
  • 如何在 GCC C++ 中编写多行内联汇编代码?

    这看起来不太友好 asm command 1 command 2 command 3 我真的必须在每一行加上双引号吗 另外 由于多行字符串文字在 GCC 中不起作用 我也无法欺骗它 我总是在互联网上找到一些例子 该人手动插入制表符和换行符而
  • Core i3/5/7 CPU 是否提供测量 IPC 的机制?

    至少 过去十年中的所有英特尔 CPU 都包含一组对各种事件进行计数的性能监视器 最新的 Intel CPU Core i3 i5 和 i7 又名 Nehalem 是否提供了计算每时钟指令 IPC 的机制 如果有 它们是如何使用的 如果可能的
  • PAE(物理地址扩展)如何实现大于4GB的地址空间?

    维基百科文章的摘录物理地址扩展 http en wikipedia org wiki Physical Address Extension x86 处理器硬件架构通过用于选择附加内存的附加地址线进行了增强 因此物理地址大小从 32 位增加到
  • 如何在WinMobile6上启用ARMv6非对齐访问?

    ARMv6 引入了一个很棒的功能 未对齐的内存访问 这使得代码中的某些事情变得更加简单和更快 但微软只在winCE6中提供了API 现在大多数 PDA 都基于 WinMobile6 基于 CE 5 x 默认情况下禁用未对齐访问 我尝试在 C
  • ICC 中的 -O3 会扰乱内在函数,使用 -O1 或 -O2 或相应的手动汇编即可

    这是后续这个问题 http stackoverflow com questions 49791664 o2 in icc messes up assembler fine with o1 in icc and all optimizatio
  • 难以理解汇编命令“加载有效地址”[重复]

    这个问题在这里已经有答案了 可能的重复 LEA 指令的目的是什么 https stackoverflow com questions 1658294 whats the purpose of the lea instruction LEA指
  • 68000 汇编语言 - CMPI.B

    What are the contents of the CCR and D3 after the following instructions sequence executes Perform the calculation by ha
  • 比“add esp, 4”更小的指令

    又是我 我的程序中有很多 add esp 4 我正在尝试减小它的大小 是否有任何更小的指令可以替代 add esp 4 pop edx 或者您不介意破坏的任何其他整数寄存器 这就是现代编译器实际上所做的 https stackoverflo
  • gcc 删除内联汇编代码

    看起来 gcc 4 6 2 删除了它认为函数中未使用的代码 test c int main void goto exit handler asm volatile jmp 0x0 exit return 0 拆解main 0x0804840
  • 如何反汇编、修改然后重新组装 Linux 可执行文件?

    无论如何 这可以做到吗 我使用过 objdump 但它不会产生我所知道的任何汇编器都可以接受的汇编输出 我希望能够更改可执行文件中的指令 然后对其进行测试 我认为没有任何可靠的方法可以做到这一点 机器代码格式非常复杂 比汇编文件还要复杂 实
  • x86 程序集 Pushl/popl 不适用于“错误:后缀或操作数无效”

    我是汇编编程的新手 正在努力解决编程基础 http savannah nongnu org projects pgubook 在带有 GNU 汇编器 v2 20 1 的 Ubuntu x86 64 桌面上 我已经能够汇编 链接执行我的代码
  • 将十进制转换为十六进制

    首先 这是家庭作业 我正在尝试将 5 位数字读入寄存器 bx 假定该数字不大于 65535 16 位 以下是我尝试这样做的方法 但是 当我尝试打印该号码时 我仅打印输入的最后一位数字 这让我猜测 当我向 bx 添加另一个数字时 它会覆盖以前
  • 如何将 asm 着色器编译为 fxo 文件?

    我有一个已编译的 fxo 着色器 我正在尝试对其进行稍微编辑 仅调整一些常量 使用 fxdis https code google com archive p fxdis d3d1x https code google com archiv

随机推荐

  • JavaFX 使用线程和 GUI

    我在使用 JavaFX 和线程时遇到问题 基本上我有两个选择 与Tasks or Platform runLater 我认为Platform runLater应用于简单 短期任务 并且Task对于较长的 但是 我无法使用其中任何一个 当我打
  • 如何使用 SQL 从字符串中提取数字

    我有一个字符串 string TEST RESULTS TEST 1 RESULT 1 除了数字之外 字符串 文本保持不变 需要 TEST 中的 1 需要结果中的 1 用于如下查询 SET sql SELECT FROM TABLE WHE
  • Windows(XP、7 等)中的数据包过滤

    如何在 Windows 中过滤 允许 拒绝等 传出数据包 我想搜索 TCP 或 UDP 数据包类型以在数据段中查找 例如 387602304fd236e048125453b1fa10c980e9dad4fa7f3f5dd2497c2e8b2
  • 自定义 WP 图像编辑小部件

    在编辑包含图像的帖子时 WP 会在图像上附加一个属性检查器图标 以允许编辑基本属性 例如大小 对齐方式 链接等 我想知道侵入此对话框屏幕并向链接区域添加一些自定义编程有多困难 我想在那里添加一个弹出菜单 只需单击一个按钮 位于现有的 链接到
  • 如何更改 Android 中 Spinner 控件的下拉箭头箭头?

    我正在编写一个 Android 应用程序 其中使用 Spinner Control 我通过创建自己的列表来自定义微调器控件 我想更改微调器控件旁边的下拉箭头 谁能帮助我如何更改微调控件的下拉箭头 我想用自己的箭头图像替换该箭头 您必须创建一
  • Assembly.GetTypes() 抛出异常

    装配有什么作用GetTypes 做幕后 假设程序集已加载到AppDomain还需要从物理DLL中读取吗 大会清单有什么作用 像这样迭代整个程序集 AppDomain CurrentDomain GetAssemblies SelectMan
  • 在 GNU Make 中创建逗号分隔列表

    我有一个带有一组布尔值的 Makefile 必须使用它们来控制外部应用程序的标志 问题是该标志必须作为逗号分隔的字符串传递 像这样的东西 非工作伪代码 WITH LIST WITHOUT LIST ifeq BOOL A y Append
  • 简单的引用计数:智能指针

    我想使用智能指针实现简单的引用计数 变量pointer表示指向存储对象的指针 reference count表示对象的副本总数 如果我们使用 NULL 初始化一个对象 reference count 1 else reference cou
  • NGINX try_files 不传递给 PHP

    我有一个非常简单的 PHP 网站 about php index php project project one php project two php projects php 以及以下 nginx 配置 仅显示相关部分 location
  • 如何调试 POST 请求上的 net::err_failed/415 Unsupported Media Type 错误?

    我们有一个 API 由我们团队的后端开发人员制作 我正在尝试在 Vue 应用程序中使用它 之前我已经成功做了一些GET通过以下方式向 API 发出请求axiosHTTP客户端 https github com axios axios 所以我
  • 为什么允许指向不完整类型的指针而不是不完整类型的变量?

    为什么以下内容是合法的 typedef struct a aType struct a int x aType b 以及以下违法行为 void main typedef struct a aType aType someVariable s
  • 如何更改 CTabCtrl 选项卡颜色?

    你好 新年快乐 周四之前说是可以接受的 我正在尝试更改选项卡的颜色CTabCtrl班级 我正在尝试创建自己的 ReskinCTablCtrl 以便我可以在单独的类中调用它并在整个程序中轻松使用它 目前我可以更改背景颜色CTabCtrl但我无
  • MATLAB 库与现有库冲突 - CMake 崩溃

    我正在 Ubuntu 16 04 64 位机器上处理 C 代码 作为代码的一部分 我必须调用 Matlab 我使用 libmat 和 libmx 库来实现 当向 CMake 提供这些库的路径时 我收到 CMake 的警告 指出现有库可能会发
  • 如何正确pickle一个namedtuple实例

    我正在学习如何使用泡菜 我创建了一个命名元组对象 将其附加到一个列表中 并尝试腌制该列表 但是 我收到以下错误 pickle PicklingError Can t pickle
  • log4j:ERROR 转换日期时发生错误

    我在日志中发现了这个异常 log4j ERROR 转换日期时发生错误 java lang NullPointerException 在 java lang System arraycopy 本机方法 在 java lang Abstract
  • 在前端翻译我的 magento 自定义模块

    我已经做了一个 magento 自定义模块 我想为其进行翻译 我怎样才能做到这一点 而不创建另一个翻译模块 多谢 您可以使用内置的翻译方法并在模板中定义所有字符串 如下所示 如果您需要在类或块中使用字符串 您可以从辅助类中获取上下文 如下所
  • 连接两个表后访问所有数据并使用 linq 将它们分组

    我有两张桌子 TableA aId aValue TableB bId aId bValue 我想通过以下方式加入这两个表aId 然后从那里将它们分组bValue var result from a in db TableA join b
  • 添加一个新列并用 Oracle SQL 中另一列的一部分填充它

    我想在表中添加一个新列 并用另一列的最后 3 个字符填充它 两者都是 varchar 源列应保持不变 我想避免创建临时列 而是想了解如何在单个查询中执行此操作 谢谢 最好使用虚拟列 https oracle base com article
  • Ajax 侦听器事件 valueChange 似乎触发 onClick 而不是 onChange

    我有一个想要显示的嵌套问题列表 最初 我显示 1 级问题 然后根据用户对其父问题的回答显示子问题 所有问题都有一个单选按钮 有些问题有一个输入框 用于在用户选择 是 时显示附加信息 这是我的带有嵌套数据表的 JSF 代码 请注意 我已经取消
  • 克服 x86 idiv #DE 异常

    回复 x86 汇编语言 我有三个 32 位有符号数 n1 n2 和 n3 我想对 n1 乘以 n2 进行 imul 以获得 64 位带符号的结果 然后我想将该 64 位结果除以 n3 问题是 如果 64 位有符号结果足够大和 或 n3 足够