Environment:
gcc 6.1
compiling for 64bit i386
optimizations: -O2
Consider this simple bit of code (from
https://stackoverflow.com/a/45656087/2189500):
#include <stdio.h>
int getStringLength(const char *pStr){
int len;
__asm__ (
"repne scasb\n\t"
"not %%ecx\n\t"
"dec %%ecx"
:"=c" (len), "+D"(pStr)
:"c"(-1), "a"(0)
);
return len;
}
int main()
{
char buff[50] = "hello world";
int a = getStringLength(buff);
printf("%s: %d\n", buff, a);
}
This code works as expected and prints out 11. Yay.
However, if you add "buff[4] = 0;" before the call to getStringLength,
it STILL prints out 11 (when optimizations are enabled), when it should
print 4.
I would expect this kind of behavior if the asm were in 'main.' But it
has always been my understanding that function calls performed an
implicit memory clobber. The fact that this clobber goes away during
inlining means that code can stop working any time the compiler makes a
different decision about whether or not to inline a function. Ouch.
And before somebody asks: Adding "+m"(pStr) does not help.
The result is that (apparently) you can NEVER safely pass a buffer
pointer to inline asm without using the memory clobber. If this is
true, I don't believe it is widely known.
Given how 'heavy' memory clobbers are, I would hope that only pointers
that have 'escaped' the function would get flushed before a function
call. But not flushing *anything* seems very bad.
dw