当前位置: 首页 > 知识库问答 >
问题:

为什么ret会随着优化而消失?

汝飞
2023-03-14
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) 

共有1个答案

左华灿
2023-03-14

我假设64bit...,数组在rdi中,透镜在ESI中。

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

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

但是执行会从非空函数(suma)的末尾脱落,这是未定义的行为,因此现代GCC只是放弃并省略ret指令。它假设执行永远不能采用该路径(因为未定义的行为),并且不麻烦为其生成代码。

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

令人惊讶的是,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源代码中没有被使用或做了任何事情。

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         

返回0;suma的末尾,它和main的末尾带有xorl%eax,%eaxret,但当然main仍然完全中断,因为内联asm没有使用任何输入约束。

 类似资料:
  • 我有一个正在运行的Spark Streaming应用程序,它使用mapWithState函数来跟踪RDD的状态。该应用程序可以正常运行几分钟,但随后会崩溃 我观察到,Spark应用程序的内存使用量随着时间的推移呈线性增加,尽管我已经为mapWithStateRDD设置了超时。请参阅下面的代码片段和内存使用情况- 如果每个RDD都有一个显式超时,为什么内存会随着时间线性增加? 我已经尝试增加内存,但

  • 我们最近在大学里做了一个关于几种语言的编程专题的讲座。 讲师写下了以下功能: 虽然我完全理解就可读性而言这也是非常糟糕的风格,但他的主要观点是,这部分代码在生产代码中工作得很好,直到它们实现了高优化级别。然后,代码将什么也不做。 他说所有对变量< code>tmp的赋值都会被编译器优化掉。但是为什么会这样呢? 我知道在某些情况下,变量需要声明为易失性,以便编译器不会触及它们,即使他认为它们从未被读

  • 因此,我从文件夹中链接了两个HTML图像:images/但是在javascript中,我试图让骰子在每次刷新后随机更改这些图像。我不知道为什么它不起作用 下面是HTML代码 下面是js代码 注意:我是一个新的学习者,仍在努力理解javascript。谢谢你谦虚的回答和帮助。如果解释得简单一点,我就可以理解了。 修复上面的代码后 我在刷新页面时遇到问题这就是它显示的内容 在此处输入图像描述

  • 我有一个模态组件,当不同的组件突变字段时,我被触发。我有一个getter在我的Vuex商店叫。模态被从称为的本地数据栏中驱动出来,我已经将其设置为getter。我正在检查的值,并且在我触发modal之后它是,但是数据仍然是false。我到底做错了什么?

  • 为什么输出的 vsnprintf 的返回值随着执行次数不同而变化呢? man vsnrpintf 手册上说的返回值是写入最终的字符串长度(如下截图中:the final string),但是实际测试并不是? 按文档说法:返回值应该为3; 实际测试结果:不为3,也不为10,而是14、15、16这样变化的数。 输出: ./a.out ====res1=10 ====res2=16, buf=sa ./

  • 我目前正在工作的一个分配的项目,以创造一个抽搐tac脚趾游戏在Java。这是我到目前为止,所有的代码工作相当好,游戏和它的功能工作非常好。我应该记录X胜、O胜和平局;然而,这似乎是问题所在。由于某种原因,即使我指定了计算机模拟的tic tac toe游戏应该有1000次迭代,x胜、o胜和平局加起来从来不是1000。它总是一个非常接近1000的数字,但我不知道为什么它总是变化。下面是我在main类中