【发布时间】:2016-05-07 06:10:22
【问题描述】:
回复:x86 汇编语言 -
我有三个 32 位有符号数:n1、n2 和 n3。
我想通过 n2 模拟 n1 以获得 64 位签名结果。
然后我想通过 n3 将 64 位结果 idiv。
问题在于,如果 64 位有符号结果足够大和/或如果 n3 足够小,则会导致溢出并且 idiv 会抛出 #DE 异常。
如果 idiv 只是将 #DE 设置为溢出,我可以检查以确认 ((n1 * n2) / n3) * n3 + ((n1 * n2) mod n3) = (n1 * n2)。如果没有,就会发生溢出,我可以进行相应的处理。
但#DE 不适合与其他人相处。当它出现时,它会报告“程序已停止工作”,然后将您踢出。
所以我要么需要在进行除法之前找到某种方法来预先检查 idiv 是否会导致溢出,要么我需要在汇编语言中执行相当于 try ... catch 的操作。
我已经搜索过互联网(包括这里),但总体上几乎没有找到相关信息;没有什么特别有用的。
我尝试将代码内联到 c++ try ... 中,但无济于事 - 它仍然报告“程序已停止工作”,然后将你踢出。
以两个支持文件为例:
// 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
此文件运行完成并产生正确的结果:
// 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”没有捕获溢出,而是系统报告“程序已停止工作”,然后将您踢出。
任何帮助将不胜感激。
【问题讨论】:
-
在 Cygwin 的 Windows 上使用 GCC?明威? MSYS2?还是其他一些 Windows 环境?
-
你知道那些
asm语句不安全,对吧?他们破坏寄存器而不用操作数约束告诉编译器。如果您已经知道这一点,那么对 asm 语句的一个小评论会很好地避免未来的读者觉得有必要向您指出这一点。 (或者通过复制代码并实际使用类似的东西)。 -
在 Windows 上,您必须使用 GCC 不支持的操作系统的结构化异常处理 (SEH) 工具。您可以使用 Microsoft 的 C/C++ 编译器和
__try和__except关键字来捕获 SEH 异常。在 Linux 上,您需要使用信号处理程序。 -
无论您使用的是 32 位还是 64 位代码,Windows 下的 SEH 处理都是完全不同的。 (如果你的目标是 ARM 或其他一些非 x86 CPU,则不同。)如果你不能使用隐藏这些实现细节的
__try和__except,你需要清楚你是否正在创建一个32 位 x86 或 64 位 x64 Windows 可执行文件或两者兼有。 -
我不确定你想说什么。无论您是否恢复,Michael Petch 链接的 32 位 SEH 宏和类在 64 位可执行文件中都不起作用,所以正如我所说,您需要明确您实际构建的内容。如果您只在出现异常后中止,您可以使用
AddVectoredExceptionHandler安装类似 Unix 信号的处理程序。但是,如果您创建的不是 32 位 x86 可执行文件,那么您可能仍需要为您的程序集函数创建 SEH 展开信息(根据 Microsoft 的调用约定),因为“矢量化”异常基于 SEH。
标签: assembly x86 try-catch overflow