Unix表示怀疑-关于以下程序的执行 [英] Unix signals doubt - on the execution of the below progem

查看:214
本文介绍了Unix表示怀疑-关于以下程序的执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个下面的程序

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

int x = 1;

void ouch(int sig) {
    printf("OUCH!  dividing by zero!\n");
    x = 0; 
}

void fpe(int sig) {
    printf("FPE!  I got a signal: %d\n",sig);
    psignal(sig, "psignal");
    x = 1; 
}

int main(void) {
    (void) signal(SIGINT, ouch);
    (void) signal(SIGFPE, fpe);

    while(1)
    {
        printf("Hello World: %d\n",1/x);
        sleep(1);
    }
}

问题:在执行该程序时-当我从终端向程序提供SIGINT时-" OUCH!除以零! "输出-如预期. 接下来的消息是 "FPE!我收到一个信号:8 psignal:浮点异常". 并且此消息持续不断-不会停止.我的疑问是在调用fpe信号处理程序后,我将x设置为1.因此,我希望Hello World应该显示在输出中.

Problem: While executing this program - when I give a SIGINT from the terminal to the program - the ""OUCH! dividing by zero! " is output - as Expected. the next message is the "FPE! I got a signal: 8 psignal: Floating point exception " . and this message goes on and on - doesn't stop. My doubt is after calling the fpe signal handler , I set x to be 1 . I hence expect Hello World should be displayed in the output.

下面是我得到的输出记录:

Below is a transcript of the output I am getting :

Hello World: 1
Hello World: 1
^COUCH!  dividing by zero!
FPE!  I got a signal: 8
psignal: Floating point exception
FPE!  I got a signal: 8
psignal: Floating point exception
FPE!  I got a signal: 8
psignal: Floating point exception
^COUCH!  dividing by zero!

.
.
.
.

推荐答案

输入信号处理程序后,会将程序计数器(指向当前执行指令的CPU寄存器)保存在被零除的位置.忽略信号会将PC恢复到完全相同的位置,在该位置上再次(又一次又一次)触发信号.

When the signal handler is entered, the program counter (CPU register pointing at the currently executing instruction) is saved where the divide-by-zero occurred. Ignoring the signal restores the PC to exactly the same place, upon which the signal is triggered again (and again, and again).

此时,"x"的值或波动率无关紧要-零已被转移到CPU寄存器中,可以执行除法.

The value or volatility of 'x' is irrelevant by this point - the zero has been transferred into a CPU register in readiness to perform the divide.

人2信号指出:

根据POSIX,在忽略了kill(2)或raise(3)函数未生成的SIGFPE,SIGILL或SIGSEGV信号之后,进程的行为是不确定的.整数除以零将产生不确定的结果.在某些架构上,它将生成SIGFPE信号. (也将最负的整数除以-1可能会生成SIGFPE.)忽略此信号可能会导致无限循环.

如果您使用debug标志进行编译,我们可以在gdb中看到这一点:

We can see this in gdb if you compile with the debug flag:


simon@diablo:~$ gcc -g -o sigtest sigtest.c 
simon@diablo:~$ gdb sigtest
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...

默认情况下,gdb不会将SIGINT传递给该进程-更改此设置,使其看到第一个信号:

By default gdb won't pass SIGINT to the process - change this so it sees the first signal:


(gdb) handle SIGINT pass
SIGINT is used by the debugger.
Are you sure you want to change it? (y or n) y

Signal        Stop  Print   Pass to program Description
SIGINT        Yes   Yes Yes     Interrupt

走吧:


(gdb) run
Starting program: /home/simon/sigtest 
x = 1
Hello World: 1

现在让我们中断一下:


^C
Program received signal SIGINT, Interrupt.
0xb767e17b in nanosleep () from /lib/libc.so.6

并继续进行分度:


(gdb) cont
Continuing.
OUCH!  dividing by zero!
x = 0

Program received signal SIGFPE, Arithmetic exception.
0x0804853a in main () at sigtest.c:30
30              printf("Hello World: %d\n",1/x);

检查'x'的值,然后继续:

Check the value of 'x', and continue:


(gdb) print x
$1 = 0
(gdb) cont
Continuing.
FPE!  I got a signal: 8
psignal: Floating point exception

Program received signal SIGFPE, Arithmetic exception.
0x0804853a in main () at sigtest.c:30
30              printf("Hello World: %d\n",1/x);
(gdb) print x
$2 = 1

x显然现在是1,我们仍然得到零除-怎么回事?让我们检查底层的汇编器:

x is clearly now 1 and we still got a divide-by-zero - what's going on? Let's inspect the underlying assembler:


(gdb) disassemble 
Dump of assembler code for function main:
0x080484ca :    lea    0x4(%esp),%ecx
0x080484ce :    and    $0xfffffff0,%esp
...
0x08048533 :  mov    %eax,%ecx
0x08048535 :  mov    %edx,%eax
0x08048537 :  sar    $0x1f,%edx
0x0804853a :   idiv   %ecx           <<-- address FPE occurred at
0x0804853c :  mov    %eax,0x4(%esp)
0x08048540 :  movl   $0x8048653,(%esp)
0x08048547 :  call   0x8048384 
0x0804854c :  jmp    0x8048503 
End of assembler dump.

后来,一个Google搜索告诉我们 IDIV 将值除以源操作数(ECX)的EAX寄存器.您可能会猜出寄存器的内容:

One Google search later tells us that IDIV divides the value in the EAX register by the source operand (ECX). You can probably guess the register contents:


(gdb) info registers 
eax            0x1  1
ecx            0x0  0
...

这篇关于Unix表示怀疑-关于以下程序的执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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