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);
}
Why is it that gcc inserts ret
at the end of suma()
on -O0
, but I have to add it myself on -O3
?
From gcc -v
:
gcc version 8.2.1 20181011 (Red Hat 8.2.1-4) (GCC)
Answer
I assume 64bit..., array in rdi, len in esi.
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.
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.
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.
If you add a return 0;
to the end of suma
, then main
will end with a ret
instruction.
Surprisingly, gcc only gives one warning on the Godbolt compiler explorer with -O3 -Wall:
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
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.
No comments:
Post a Comment