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

Reply via email to