问题描述
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
上添加它?
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)
推荐答案
您正在使用 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, %eax
; ret
,但是当然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.
这篇关于为什么优化后消失了?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!