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在ret
的{{1}}的末尾插入suma()
,但是我必须自己在-O0
上添加它?
来自-O3
:
gcc -v
答案 0 :(得分:6)
我假设64位...,数组在rdi中,len在esi中。
您正在使用 inline asm,而不是在__attribute__((naked,noinline))
函数中使用,因此编译器可以在所需的任何上下文中使用inline asm模板块。由于您无法使用任何输入/输出约束,并且您在不告知编译器的情况下就破坏了寄存器,除非禁用优化,否则它将完全中断。
要回答主要问题,编译器只需将suma
内联到main
中即可。它是隐式的volatile
(因为它是基本的asm语句),因此并未进行优化。
但是执行会落在非空函数(suma
)的末尾,这是不确定的行为,因此现代的GCC只是放弃并省略了ret
指令。它假定执行永远不会走那条路(由于未定义的行为),并且不会为它生成代码。
如果在return 0;
的末尾添加suma
,则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, %eax
; ret
,但当然main
仍然被完全破坏,因为内联汇编不使用任何输入约束。