Register constrained variable issue

Zoltán Kócsi zoltan@bendor.com.au
Thu Oct 13 14:50:00 GMT 2011


If one writes a bit of code like this:

int foo( void )
{
register int x asm( "Rn" );

  asm volatile ( "INSN_A %0 \n\t" : "=r" (x) );
  bar();
  asm volatile ( "INSN_B %0,%0 \n\t" : "=r" (x) : "0" (x) );
  return x;
}

and Rn is a register not saved over function calls, then gcc does not save it
but allows it to get clobbered by the calling of bar(). For example, if the
processor is ARM and Rn is r2 (on ARM r0-r3 and r12 can get clobbered by a
function call), then the following code is generated; if you don't know ARM
assembly, comments tell you what's going on:

foo:
   stmfd   sp!, {r3, lr} // Save the return address
   INSN_A  r2            // The insn generating r2's content
   bl      bar           // Call bar(); it may destroy r2
   INSN_B  r2, r2        // *** Here a possibly clobbered r2 is used!
   mov     r0, r2        // Copy r2 to the return value register
   ldmfd   sp!, {r3, lr} // Restore the return address
   bx      lr            // Return

Note that you don't need a real function call in your code, it is enough if
you do something which forces gcc to call a function in libgcc.a. On some ARM
targets a long long shift or an integer division or even just a switch {}
statement is enough to trigger a call to the support library.

Which basically means that one *must not* allocate a register not saved by
function calls because then they can get clobbered at any time.

It is not an ARM specific issue, either; other targets behave the same. The
compiler version is 4.5.3. 

The info page regarding to specifying registers for variables does not say
that the register one chooses must be a register saved across calls. On the
other hand, it does say that register content might be destroyed when the
compiler knows that the data is not live any more; a statement which has a
vibe suggesting that the register content is preserved as long as the data is
live.

For global register variables the info page does actually warn about library
routines possibly clobbering registers and says that one should use a saved
and restored register. However, global and function local variables are very
different animals; global regs are reserved and not tracked by the data flow
analysis while local var regs are part of the data flow analysis, as stated
by the info page.

So I don't know if it is a bug (i.e. the compiler is supposed to protect local
reg vars) or just misleading/omitted information in the info page?

Thanks,

Zoltan



More information about the Gcc mailing list