非常简单的代码中的“非法硬件指令”


9

在调查可疑的索赔时,我编写了这个小测试程序noway.c

int proveit()
{
    unsigned int n = 0;
    while (1) n++;
    return 0;
}

int main()
{
    proveit();
    return 0;
}

测试一下,我得到:

$ clang -O noway.c
$ ./a.out
zsh: illegal hardware instruction  ./a.out

笏。

如果我不进行优化就进行编译,则它会按预期挂起。我看了看程序集,没有所有的花哨main功能,函数看起来像这样:

_main:                                  ## @main
    pushq   %rbp
    movq    %rsp, %rbp
    ud2

哪里 ud2显然是一个指令专门为未定义行为。前面提到的可疑声明“永不返回的函数是UB”得到了增强。我仍然很难相信。真!?您不能安全地编写自旋循环吗?

所以我想我的问题是:

  1. 这是对正在发生的事情的正确阅读吗?
  2. 如果是这样,有人可以指出我的官方资源吗?
  3. 您希望在哪种情况下进行这种优化?

相关资料

$ clang --version
Apple clang version 11.0.0 (clang-1100.0.20.17)
Target: x86_64-apple-darwin18.6.0
Thread model: posix
InstalledDir: /Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

3
IIRC,签名的int溢出是UB。
wildplasser

1
^^^^即int n = 0===> unsigned int n = 0;还是更好while (1);
。.– WhozCraig

1
嗯...编译器资源管理器clang使用-O gcc.godbolt.org/z/NTCQYT获取自我目标跳转指令,并且在没有该指令的情况下进行逐行转换。在许多版本中似乎保持一致。但是我还记得(尽管不会查找)C标准说,如果无副作用,则非终止是ub 。这是Hans Boehm的解释,它允许进行某些其他不可能的编译器优化:open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm
基因

1
未定义的行为是有符号整数溢出,而不是无限循环。您可以使用unsigned int
MM

2
@Gene我不这么认为。可以假定具有非const控制表达式的无副作用循环终止(port70.net/~nsz/c/c11/n1570.html#6.8.5p6),但是忙循环应该可以。UB处于整数溢出状态,尽管我无法使用UD指令重现该示例。
PSkocik

Answers:


3

如果您为问题中的代码获取ud2,则编译器不是合格的C编译器。您可以报告编译器错误。

请注意,在C ++中,此代码实际上是UB。添加线程(分别为C11和C ++ 11)时,对任何线程(包括非多线程程序的主要执行线程)都提供了向前进度保证。

在C ++中,所有线程都必须最终进展,没有例外。但是,在C语言中,不需要执行其控制表达式为常量表达式的循环。我的理解是C添加了此异常,因为在嵌入式编码中使用while(1) {}挂起线程了。

类似问题,答案更详细


是的,我确实ud2从C代码中得到了,但是感谢您提供有关C ++向前进度保证的信息(看来我将能够研究该术语),这是我真正要问的,但是,嗯,已经优化了我正在准备问题。
luqui

我认为标准委员会试图说的一个更好的措词是,如果将某个循环中的所有内容推迟到某个操作之后不会明显地影响程序行为,那么将整个循环的执行推迟到该操作之后就不会被认为是可观察到的行为改变。
超级猫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.