Please help. extended asm syntax unclearly documented.

Carlo Wood carlo@alinoe.com
Mon Dec 16 05:12:00 GMT 2002


Hi,

I am having a very hard time understanding "extended asm" documentation.
I've studied it several days now and it seems that information missing;
things remain unclear :(.

For example, I still have the following questions:

1) Is it possible to defined a __asm__ definition that
   specifies what will be the value of a certain (output)
   register afterwards?  And if is, how?
   My guess is that this is not possible, but that would
   a missing feature then imho.

   Example:

   __asm__ ("rep; stosl", ...

   The use of 'rep' garantees that after this assembly code
   %ecx equals to 0.  But how to tell gcc that?
   Same thing when we do:

   __asm__ ("xorl %%eax,%%eax; rep; stosl", ...

   One can add "%eax" to the clobber list, but how to tell
   gcc that after this asm the value of %eax equals 0?
   Often, in this case, %eax is passed as input:
   "a" (0)
   causing gcc to generate the leading 'xorl %%eax,%%eax'
   itself, and hence knowing that eax is (still) zero
   after the instruction if you don't specify it as output,
   but that prefends using %eax as input register.

2) How to specify the clobber of a region of memory?
   From the documentation is seems that this is not
   possible but I am not sure.
   
   For example, lets use the asm code that sets a given
   memory range to zero:

  int __d0, __d1;
  __asm__ __volatile__
  ("cld ; rep ; stosl"
    : "=c" (__d0),
      "=D" (__d1),
    : "a" (0),
      "0" (count),
      "1" (address)
    : "memory", "cc"
  );

  this is the best I can make of it.  It will fill
  *address and up (in total 'count' integers) with 0.
  It does NOT tell gcc that after this, ecx will be
  0, edi will be address + count and that the memory
  clobber is limited to the range [address, address + count>.

  How can I tell gcc that only that specific range is
  clobbered?

  That this is unclearly documented might also show
  from the fact that even the linux kernel contains
  questionable code.  For example, from
  include/asm-i386/posix_types.h (kernel 2.4.18):

  define __FD_ZERO(fdsetp) \
  do { \
	  int __d0, __d1; \
	  __asm__ __volatile__("cld ; rep ; stosl" \
			  :"=m" (*(__kernel_fd_set *) (fdsetp)), \
			    "=&c" (__d0), "=&D" (__d1) \
			  :"a" (0), "1" (__FDSET_LONGS), \
			  "2" ((__kernel_fd_set *) (fdsetp)) : "memory"); \
  } while (0)


  It seems that they forgot to add "cc", and I don't understand
  why they added the '&' in "=&c" and "=&D" in this case :(.
  More importantly however - they added an output:
  "=m" (*(__kernel_fd_set *) (fdsetp))
  which seems totally redudant together with the "memory" as clobber.
  Besides, that is only a single 32bit word in memory and not the
  whole range :/.


Consider the actual documentation of gcc info:

"If your assembler instruction modifies memory in an unpredictable
 fashion, add `memory' to the list of clobbered registers. This will
 cause GCC to not keep memory values cached in registers across the
 assembler instruction."

That seems clear so far.  Then we get:

"You will also want to add the volatile keyword if the memory affected
 is not listed in the inputs or outputs of the asm, as the `memory'
 clobber does not count as a side-effect of the asm."

I am totally lost here.  Add the volatile where?  And why does it make
a difference if the memory is or is not listed as input/output?
Can someone please explain this last sentence to me with examples?

-- 
Carlo Wood <carlo@alinoe.com>

PS Please CC me, I am not subbed to this list.



More information about the Gcc mailing list