Re: Inline assembler + register values

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Andrew Haley wrote:
> On 01/24/2012 11:35 AM, Konstantin Vladimirov wrote:
>> This problem is backend independent, so I build reproduction in x86
>> backend. Consider code:
>>
>> int func(int x);
>>
>> int test(int x, int *data)
>> {
>>   int retval;
>>   register int *buffer asm ("eax");
>>
>>   buffer = data;
>>   retval = func(x);
>>   __asm__ __volatile__ (".internal_label _t." "4096"
>>                         ".%0.%1.%2:;nop"::"ri" (buffer), "ri" (4137), "ri" (4));
>>   return retval;
>> }
>>
>> here nop will be replaced for something, that essentially uses %eax,
>> but it is not actually required for minimal reproduction.
>>
>> being compiled with gcc (SUSE Linux) 4.5.0 20100604 [gcc-4_5-branch
>> revision 160292]
>>
>> with following options:
>>
>> gcc -m32 -O2 -S -fomit-frame-pointer reprox86.c
>>
>> yields assembler:
>>
>>   .type test, @function
>> test:
>>   subl  $28, %esp
>>   movl  32(%esp), %eax
>>   movl  %eax, (%esp)
>>   call  func                           // <--- here eax is clobbered
>>   .internal_label _t.4096.%eax.$4137.$4:;nop 0
>>   addl  $28, %esp
>>   ret
>>
>> That looks quite odd. I have a question -- why compiler doesn't save &
>> restore buffer (i.e. %eax) value around function call, when we
>> specifically pointed to %eax usage in the inline assembler
>> instruction?
> 
> Well, hold on: you've said that you want buffer to live in register
> EAX for the entire duration of test().  GCC assumes that you know what
> you are doing, know that EAX is call-clobbered, and are using EAX
> because you want to pass arguments to func() in EAX.  In other words,
> it's not a bug, it's a feature.

No, it's a bug.

The OP says that %eax is not used to pass an argument to func().

It is fine if %eax is clobbered while calling func() if tha ABI says so.

The "asm" in the local definition of buffer should have no effect except at the
time it is used as operand to an inline assembler statement. This means that
buffer might live anywhere before the inline assembler and has to be
saved/restored around the function call. When the inline assembler is executed,
it is ensured that buffer is loaded with %eax.

A local asm variable does *not* say "this variable will be held in the register
throughout the whole function or lifetime of the variable". Is just ensures
that the variable is reloaded to respective asm operand.

One more example:

void foo()
{
  register int var asm ("eax");
  // following line is wrong because %eax is not tied to var
  __asm__ __volatile__ ("use %eax");
}

void foo()
{
  register int var asm ("eax");
  // following ensures %eax holds var and %0 prints %eax
  __asm__ __volatile__ ("use %%eax, %0"::"r"(var));
}


Notice that %eax is not a fixed register. The semantics might be different for
fixed register.

Johann


[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux