More inline assembly caveats ('asm' tutorial)

Pavel Pisa ppisa4lists at pikron.com
Thu Feb 5 01:23:16 UTC 2009


Hello Till,

I have not time to think much more about this, but if you want
buf address in one register, buf+len in another register and code
is dependant memory content, then


   asm volatile( <actual assembly code> :: "a"(buf), "a"(buf+len) , "o"(*buf));

adding dummy (unused in assembly) "o" constrain operand should work.
If the code changes buffer content in place, then 

   asm volatile( <actual assembly code> :"=o"(*buf): "a"(buf), "a"(buf+len) , "0"(*buf));

or

   asm volatile( <actual assembly code> :"+o"(*buf): "a"(buf), "a"(buf+len) );

should be OK. The problem could be specification of real size of
the considered area. One possibility is to use

   struct  affected_size { char x[1000];};

   asm volatile( <actual assembly code> :"+o"(*(struct  affected_size *)buf): "a"(buf), "a"(buf+len) );

Am I wrong with something there?

Discussion at GCC mailing list speaks about "m" constrain side effects,
but "o" is generally defined as offsetable address for all architectures.

Thanks in advance for comments about possible problems of such code.

Best wishes,

                 Pavel


On Wednesday 04 February 2009 23:12:16 Till Straumann wrote:
> Here's a new morsel:
>
> The mvme167 BSP does something like that
>
> void _BSP_output_char(char c)
> {
> char cr = '\r';
>
>   _167Bug_pollWrite(&c, 1);
>
>   /* convert '\n' -> '\n' '\r' sequence */
>
>   if ( '\n' == c )
>     _167Bug_pollWrite(&cr,1);
>
> }
>
>
> In 4.9 (gcc 4.3.2) this doesn't work anymore.
> Here's why:
>
> _167Bug_pollWrite contains inline assembly;
> something like
>
> void _167Bug_pollWrite(const char *buf, int len)
> {
>
>    asm volatile( <actual assembly code> :: "a"(buf), "a"(buf+len) );
>
> }
>
> Newer gccs are 'smart' enough to realize that
> the value the 'cr' variable was initialized with
> is never used and hence optimizes storing the '\r'
> character into memory away (because it is NOT
> smart enough to actually understand the inline
> assembly code and realize that the value is needed
> there).
>
> The naive approach here would be to proceed as
> suggested by the gcc manual and add 'len' bytes
> of memory starting at 'buf' to the list of
> input operands. HOWEVER: this does NOT necessarily
> do what you want; the actual semantics are
> different for each architecture and may have
> side-effects which are undocumented.
>
> For an discussion and explanation consult this thread:
>
> http://gcc.gnu.org/ml/gcc/2008-03/threads.html#00976
>
> In the above case I could gcc 4.3.2 get to do
> what is needed (i.e., storing the '\r' character
> in memory) by either
>
> 1) declaring the 'cr' variable 'volatile'
>
> volatile const char cr = '\r';
>
> 2) adding a general 'memory barrier' but this may be
>    more costly than 1) or having a proper way to
>    tell gcc that the inline asm reads or writes
>    a specific memory region (again: adding a memory
>    input/output operand may have OTHER SIDEEFFECTS
>    which are not documented in the gcc manual and
>    differ for each architecture).
>
>
> const char cr = '\r';
>
> asm volatile("":::"memory");
>
>
> 3) In this particular example, our variable is actually
>    constant so we could make it a static variable and
>    hope it is actually initialized:
>
> static const char cr = '\r';
>
>
> 4) Same rationale: use a static string
>
>    _167Bug_pollWrite("\r",1)
>
> Hope this helps alerting people that inline assembly
> has to be used with extreme care and is best avoided.
>
>
> -- Till
>
> PS: This was filed as PR#1370
>
> https://www.rtems.org/bugzilla/show_bug.cgi?id=1370
> _______________________________________________
> rtems-users mailing list
> rtems-users at rtems.com
> http://rtems.rtems.org/mailman/listinfo/rtems-users





More information about the users mailing list