在C程序中除以零会导致错误消息的异常终止Floating point exception (core dumped).这对于浮点除法并不足为奇,但为什么在整数除以零时会这样说呢?整数除法实际上是否使用引擎盖下的FPU?
(顺便说一下,这都是在x86下的Linux上.)
在内核2.6.11.5中,除零异常处理程序设置为:
set_trap_gate(0,÷_error);
Run Code Online (Sandbox Code Playgroud)
根据"了解Linux内核",用户模式进程无法访问英特尔陷阱门.但是用户模式进程很可能也会生成一个divide_error.那么为什么Linux以这种方式实现呢?
[编辑]我认为问题仍然是开放的,因为set_trap_gate()将IDT条目的DPL值设置为0,这意味着只有CPL = 0(读取内核)代码才能执行它,因此我不清楚如何从该处理程序调用此处理程序用户模式:
#include<stdio.h>
int main(void)
{
int a = 0;
int b = 1;
b = b/a;
return b;
}
Run Code Online (Sandbox Code Playgroud)
这是编译的gcc div0.c.输出./a.out是:
浮点异常(核心转储)
因此看起来这不是由0陷阱代码划分处理的.
我的任务是表达一些看似奇怪的C代码行为(在x86上运行).我可以很容易地完成其他所有事情,但这个让我很困惑.
代码段1输出
-2147483648Run Code Online (Sandbox Code Playgroud)int a = 0x80000000; int b = a / -1; printf("%d\n", b);
代码片段2没有输出任何内容,并给出了一个
Floating point exceptionRun Code Online (Sandbox Code Playgroud)int a = 0x80000000; int b = -1; int c = a / b; printf("%d\n", c);
我很清楚Code Snippet 1(1 + ~INT_MIN == INT_MIN)的结果的原因,但是我不太明白整数除以-1如何生成FPE,也不能在我的Android手机(AArch64,GCC 7.2.0)上重现它.代码2只输出与代码1相同,没有任何例外.它是x86处理器的隐藏bug功能吗?
该任务没有告诉任何其他内容(包括CPU架构),但由于整个课程基于桌面Linux发行版,您可以放心地认为它是一个现代的x86.
编辑:我联系了我的朋友,他在Ubuntu 16.04(Intel Kaby Lake,GCC 6.3.0)上测试了代码.结果与所指定的任何内容一致(代码1输出所述内容,代码2与FPE崩溃).
我对ARM处理器的内部细节不是很熟悉,但是我不了解Nvidia Jetson Nano开发板上的以下行为。
C代码示例...
//main.c
#include <stdio.h>
int main()
{
int fred = 123;
int i;
for(i = -10 ; i <= 10 ; i++)
printf("%d / %d == %d\n", fred, i, fred / i);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译:
gcc main.c -ggdb
Run Code Online (Sandbox Code Playgroud)
运行生成的a.out可执行文件将产生以下输出...
123 / -10 == -12
123 / -9 == -13
123 / -8 == -15
123 / -7 == -17
123 / -6 == -20
123 / -5 == -24
123 / -4 == -30
123 / …Run Code Online (Sandbox Code Playgroud) 我今天进行了测试,我唯一不理解的问题是将双字转换为四字.
这让我思考,为什么/我们什么时候签署扩展乘法或除法?另外,我们何时使用像cdq这样的指令?
我正在尝试了解 x86 程序集中的中断。
我试图触发一个被零除错误,它对应于代码 0。
int $0
Run Code Online (Sandbox Code Playgroud)
我期望这与除以零具有相同的行为。
movl $0, %edx # dividend
movl $0, %eax # dividend
movl $0, %edi # divisor
divl %edi
Run Code Online (Sandbox Code Playgroud)
在前一种情况下,我的程序在 Linux 上因“分段错误”和退出代码 139 而崩溃。在后一种情况下,我的程序因“浮点异常”而崩溃,并在 Linux 上退出代码 136。
如何使用中断触发与使用零除数调用 div 指令相同的错误?
我有一个像这样的示例代码:
global _start
section .text
_start:
div eax
int 0x80
Run Code Online (Sandbox Code Playgroud)
在编译并运行它之后,输出为:
Floating point exception (core dumped)
Run Code Online (Sandbox Code Playgroud)
我的问题是:
eax != 0 and eax == 0?Floating point exception (core dumped)什么?我不太确定分区在x86汇编中是如何工作的(GAS AT&T语法).我想做的是划分两个长,然后将商乘以除数,看看新数是否等于初始数(n/m*m = n).
movl %ebx, %eax
movl %ecx, %edx
idivl %edx
imull %ebx, %edx
cmp %edx, %ebx
je .equal
Run Code Online (Sandbox Code Playgroud)
上面的代码是我做分工的片段.ebx和ecx是我想要分割的两个计数器,eax寄存器用作除数是否正确?所以,当我写idivl%edx时,我将edx与eax分开,并得到最接近0的整数?像7/2 = 3?我读了一个地方,这个商存储在edx寄存器中,余数存储在ah寄存器中,但我还被告知,商存储在eax寄存器中,余数存储在edx寄存器中,这让我感到困惑.
虽然这里的主要问题是:我想将ebx寄存器的值除以ecx寄存器的值,我该如何处理?
谢谢!
编辑:上面的代码产生一个浮点异常
我知道在组装时必须非常小心,即这样做:
mov ah, 10h
mov al, 00h ; dividend = 1000h
mov bl, 10h ; divisor = 10h
div bl ; Integer overflow exception, /result 100h cannot fit into al
Run Code Online (Sandbox Code Playgroud)
我已经编写了一些可能不可靠的逻辑来为除法创建一个更友好的环境:
mov ah, 10h
mov al, 00h
mov bl, 10h
TryDivide:
cmp bl,ah
jna CatchClause
div bl
clc
jmp TryEnd
CatchClause:
stc
TryEnd:
Run Code Online (Sandbox Code Playgroud)
有没有人知道类似这样的事情没有实现的技术原因,我们有例外而不是标志设置/寄存器被截断?
int main()
{
int x = 5, y = 0;
int z = x / y;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我知道它是在未定义的行为下,但它是否意味着分段错误?CPU处理如何除以0大小写?
当我运行它时,我得到浮点异常(核心转储).