【问题标题】:Why ret disappear with optimization?为什么 ret 随着优化消失?
【发布时间】:2018-10-24 10:07:48
【问题描述】:
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在-O0上的suma()末尾插入了ret,而-O3上却要我自己加?

来自gcc -v

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

【问题讨论】:

  • 也许它被内联到 main 已经有一个 ret 指令。没有看到完整的结果很难猜测。
  • 我不确定,但请注意,从技术上讲,您的整个内联程序集并没有真正明确定义,因为您假设某些寄存器保存某些值,这不是一个有效的假设。跨度>
  • 我假设是 64 位...,数组在 rdi,len 在 esi。
  • this。它是内联的,但仍然生成了suma 函数的代码,并且ret 没有被删除。您是如何注意到没有带有 -O3 的 ret 的?
  • 用 objdump 反汇编

标签: c gcc assembly compiler-optimization inline-assembly


【解决方案1】:

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

您正在使用 inline asm,而不是在 __attribute__((naked,noinline)) 函数中,因此编译器可以在它想要的任何上下文中使用内联 asm 模板块。由于您没有使用任何输入/输出约束,并且您在不告诉编译器的情况下破坏了寄存器,因此除非您禁用优化,否则它将完全崩溃。

要回答主要问题,编译器只需将suma 内联到main。它是隐含的 volatile(因为它是一个基本的 asm 语句),所以它没有被优化掉。

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

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

令人惊讶的是,gcc only gives one warning on the Godbolt compiler explorer with -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 源代码中未使用或做了任何事情。

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         

return 0;suma 结尾,它和主结尾以xorl %eax, %eaxret,但当然 main 仍然完全损坏,因为内联 asm 不使用任何输入约束。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多