idiv指令的结果不同

时间:2014-08-18 12:31:22

标签: c undefined-behavior mingw-w64 integer-division

看一下这段代码

int main()
{
    int i = 1U << 31; // assume this yields INT_MIN
    volatile int x;
    x = -1;
    x = i / x; //dividing INT_MIN by -1 is UB
    return 0;
}

它在典型平台上调用未定义的行为,但“行为”与我的期望完全不同 - 它就好像它是一个无限循环。我能想到它咬人的场景。

当然undefined是未定义的,但我检查了输出程序集,它使用的是普通idiv - 为什么它没有陷阱?为了便于比较,除以零会导致立即中止。

使用Windows 7 64位和MingW64

任何人都可以向我解释这个吗?

修改

我尝试了几个选项,结果总是一样的。

这是集会:

    .file   "a.c"
    .def    __main; .scl    2;  .type   32; .endef
    .section    .text.startup,"x"
    .p2align 4,,15
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
    subq    $56, %rsp
    .seh_stackalloc 56
    .seh_endprologue
    call    __main
    movl    $-1, 44(%rsp)
    movl    $-2147483648, %eax
    movl    44(%rsp), %ecx
    cltd
    idivl   %ecx
    movl    %eax, 44(%rsp)
    xorl    %eax, %eax
    addq    $56, %rsp
    ret
    .seh_endproc
    .ident  "GCC: (x86_64-posix-sjlj, built by strawberryperl.com project) 4.8.2"

1 个答案:

答案 0 :(得分:4)

你观察到的无限循环可能是MinGW-w64中的一个错误。

MinGW-w64部分支持SEH,如果在调试器中运行代码,您将看到异常处理程序(名为&#34; _gnu_exception_handler&#34;的函数)由于无效的idiv而被调用。 (例如在gdb中运行程序并在_gnu_exception_handler上设置断点)

简单地说,这个异常处理程序在整数溢出的情况下所做的只是解除异常并在发生异常的位置继续执行(idiv)。然后再次执行idiv操作,导致相同的溢出触发相同的错误处理程序,并且您的CPU在idiv和异常处理程序之间来回切换。 (这是MinGW-w64的行为可以被视为错误的地方。)

如果你想深入了,你可以直接在源here中看到它。

值&#34; EXCEPTION_CONTINUE_EXECUTION&#34;由_gnu_exception_handler处理EXCEPTION_INT_OVERFLOW(整数溢出)时返回的是导致此行为的原因(当系统看到处理程序返回EXCEPTION_CONTINUE_EXECUTION时,它会跳回到生成异常的指令并尝试再次执行它。)

如果您对更多详细信息感兴趣,here是了解SEH如何在Windows上运行的良好资源。