Sunday, 28 May 2017

c - Why ret disappear with 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);
}


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:



: In function 'int suma(int*, int)':
:13:1: warning: no return statement in function returning non-void [-Wreturn-type]
}
^



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

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...