clang如何将具有未定义行为的代码编译为该机器代码? [英] How does clang manage to compile this code with undefined behavior into this machine code?

查看:95
本文介绍了clang如何将具有未定义行为的代码编译为该机器代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是这条推文的代码变体,只是较短的一条,并且不会造成任何损害对新手来说。我们有以下代码:

It's a variation of code from this tweet, just shorter one and not causing any damage to noobs. We have this code:

typedef int (*Function)();

static Function DoSmth;

static int Return7()
{
    return 7;
}

void NeverCalled()
{
   DoSmth = Return7;  
}

int main()
{
    return DoSmth();
}

您会看到 NeverCalled()不会在代码中调用,不是吗?这是当使用



选择clang 3.8时编译器资源管理器显示的内容。

You see that NeverCalled() is never called in the code, don't you? Here's what Compiler Explorer shows when clang 3.8 is selected with

-Os -std=c++11 -Wall

发出的代码是:

NeverCalled():
    retq
main:
    movl    $7, %eax
    retq

就像 NeverCalled()实际上是在 DoSmth()之前调用的,并将 DoSmth 函数指针设置为 Return7()函数。

as if NeverCalled() was actually called before DoSmth() and set the DoSmth function pointer to Return7() function.

如果从 NeverCalled()如下所示:

void NeverCalled() {}

然后发出的代码是这样的:

then code being emitted is this:

NeverCalled():
    retq
main:
    ud2

后者相当预期。编译器知道函数指针肯定为空,并且使用空函数指针调用函数是未定义的行为。

The latter is quite expected. The compiler knows that function pointer is surely null and calling function using a null function pointer is undefined behavior.

以前的代码并不是真正期望的。编译器决定以某种方式决定调用 Return7(),尽管它没有在任何地方直接调用,并且函数指针分配在未调用的函数内部。

The former code is not really expected. Somehow the compiler decided to have Return7() called although it's not directly called anywhere and function pointer assignment is inside function that is not called.

是的,我知道C ++ Standard允许编译器面对未定义行为的代码。

Yes, I know the compiler facing code with undefined behavior is allowed to do this by C++ Standard. Just how does it do this?

铛如何发出此特定机器代码?

How does clang happen to emit this specific machine code?

推荐答案

NeverCalled 是用词不当。可能会调用任何全局函数(例如,通过不同翻译单元中的全局对象的构造函数)。

NeverCalled is a misnomer. Any global function is potentially called (by a constructor of a global object in a different translation unit, for example).

顺便说一下,这是该TU唯一可能的方法被并入没有UB的程序中。在这种情况下, main 返回7。

Incidentally, this is the only way this TU can possibly be incorporated in a program that doesn't have UB. In this case, main returns 7.

使 NeverCalled 静态,并且 main 将编译为空代码。

Make NeverCalled static, and main will compile to empty code.

这篇关于clang如何将具有未定义行为的代码编译为该机器代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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