gus*_*avo 4 c assembly gcc inline-assembly compiler-optimization
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);
}
Run Code Online (Sandbox Code Playgroud)
为什么gcc会ret在suma()on 的末尾插入-O0,但我必须自己添加on -O3?
来自gcc -v:
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);
}
Run Code Online (Sandbox Code Playgroud)
我假设在RDI中使用64bit ...数组,在esi中使用len。
您正在使用内联汇编,而不是在__attribute__((naked,noinline))函数中使用,因此编译器可以在所需的任何上下文中使用内联汇编模板块。由于您无法使用任何输入/输出约束,并且在不告知编译器的情况下就破坏了寄存器,因此除非禁用优化,否则它将完全中断。
要回答主要问题,编译器只需内联suma到main。它是隐式的volatile(因为这是一个基本的asm语句),因此并未进行优化。
但是执行落在非空函数(suma)的末尾,后者是未定义的行为,因此现代GCC只是放弃并忽略了ret指令。它假定执行永远不会采用该路径(由于未定义的行为),并且不会为它生成代码。
如果return 0;在的末尾添加a suma,main则将以一条ret指令结尾。
令人惊讶的是,gcc仅在使用-O3 -Wall的Godbolt编译器资源管理器中发出一个警告:
<source>: In function 'int suma(int*, int)':
<source>:13:1: warning: no return statement in function returning non-void [-Wreturn-type]
}
^
Run Code Online (Sandbox Code Playgroud)
的asm输出结果main是这样,由于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
Run Code Online (Sandbox Code Playgroud)
以a return 0;结尾suma,它和主要结尾为xorl %eax, %eax;ret,但是main由于内联汇编不使用任何输入约束,因此当然还是完全坏掉了。