为什么优化后消失了? [英] Why ret disappear with optimization?

查看:162
本文介绍了为什么优化后消失了?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

int suma(int* array, int len)
{
    asm("    xor %eax, %eax           # resultado = 0   \n"
        "    xor %edx, %edx           # i = 0           \n"
        "1:  add (%rdi,%rdx,4), %eax  # res += array[i] \n"
        "    inc %edx                 # ++i             \n"
        "    cmp %edx,%esi            # i < len?        \n"
        "    jne 1b                   # repetir         \n"
//      "    ret                                        \n"
       );
}

int main()
{
    int v[100];
    return suma(v, 100);
}

为什么gcc在-O0suma()末尾插入ret,但是我必须自己在-O3上添加它?

Why is it that gcc inserts ret at the end of suma() on -O0, but I have to add it myself on -O3?

来自gcc -v:

gcc version 8.2.1 20181011 (Red Hat 8.2.1-4) (GCC) 

推荐答案

我假设64位...,数组在rdi中,len在esi中.

I assume 64bit..., array in rdi, len in esi.

您正在使用 inline asm,而不是在__attribute__((naked,noinline))函数中使用,因此编译器可以在所需的任何上下文中使用inline asm模板块.由于您无法使用任何输入/输出约束,并且您在不告知编译器的情况下就破坏了寄存器,除非禁用优化,否则它将完全中断.

You're using inline asm, and not in a __attribute__((naked,noinline)) function, so the compiler can use the inline asm template block in any context it wants. Since you failed to use any input/output constraints, and you clobber registers without telling the compiler, it will just totally break unless you disable optimization.

要回答主要问题,编译器只需将suma内联到main中即可.它是隐式volatile(因为它是基本的asm语句),因此并未进行优化.

To answer the main question, the compiler simply inlines suma into main. It's implicitly volatile (because it's a basic asm statement) so it isn't optimized away.

但是执行会落在非空函数(suma)的末尾,这是未定义的行为,因此现代GCC只是放弃并忽略了ret指令.它假定执行永远不会走那条路(由于未定义的行为),并且不会为它生成代码.

But execution falls off the end of a non-void function (suma), which is undefined behaviour, so modern GCC just gives up and omits the ret instruction. It assumes that execution can never take that path (because of the undefined behaviour), and doesn't bother generating code for it.

如果在suma的末尾添加return 0;,则main将以ret指令结尾.

If you add a return 0; to the end of suma, then main will end with a ret instruction.

出人意料地, GCC仅给出关于Godbolt编译探险与-O3 -Wall :

<source>: In function 'int suma(int*, int)':
<source>:13:1: warning: no return statement in function returning non-void [-Wreturn-type]
 }
 ^

main的结果asm输出是这样的,由于RDI为argc,因此当然完全坏了;它从未为int v[100]保留空间,因为它没有在C源代码中使用或执行任何操作.

The resulting asm output for main is this, which is of course totally broken because RDI is argc; it never reserved space for int v[100] because its unused in the C source or did anything.

main:
            xor %eax, %eax           # resultado = 0   
    xor %edx, %edx           # i = 0           
1:  add (%rdi,%rdx,4), %eax  # res += array[i] 
    inc %edx                 # ++i             
    cmp %edx,%esi            # i < len?        
    jne 1b                   # repetir         

suma的末尾带有return 0;,它的主端是xorl %eax, %eaxret,但是当然main仍然完全损坏,因为内联汇编不使用任何输入约束.

With a return 0; at the end of suma, it and main end with xorl %eax, %eax ; ret, but of course main is still totally broken because the inline asm doesn't use any input constraints.

这篇关于为什么优化后消失了?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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