How to Convert Basic asm to Extended asm

See the gcc docs for Basic asm and Extended asm for the exact syntax and a detailed description of these statements and their options.

Why Convert?

There are a number of reasons you might want to convert basic asm statements into extended asm:

One last point: If you are going to be mucking with your inline asm, take a minute to consider not using inline asm at all. Inline asm is difficult to maintain, non-portable, and can actually be slower than using C.

That said...

How to Convert (short)

The steps for the conversion are pretty straight-forward. In brief:

  1. Add a ":" after the string of your basic asm statement.
  2. If your basic asm string includes '%' characters, escape them using '%%'.
  3. On platforms that support dialects (including i386, pa, pdp11, rs6000, sh), the characters '{' '|' and '}' also need to be escaped.

There are some quibbles and quirks, but that's the heart of it.

How to Convert (long)

1) It is possible to convert a basic inline asm statement to extended by simply adding a ":" on the end:

   asm(""); /* basic */
   asm("":); /* extended */

This will give you the same semantics in extended asm as you were getting in basic (ie perform NO clobbers).

Some people have assumed (incorrectly!) that basic asm performed a clobber on registers, memory or both. That has never been the case in gcc, although other compilers may be different. If the code you are changing assumes or needs a register or memory clobber, you should explicitly add it (for example asm("sync":::"memory");).

Note that all basic asm statements are implicitly volatile (whether they have the volatile keyword or not). Also, extended asm statements that have no outputs are also implicitly volatile. So the two statements above would still be the same if either or both contained the volatile keyword.

It may be better aesthetically to write this instead:

   asm("" : : :);

Functionally it is the same as using a single colon, but it may suggest that you considered adding clobbers and deliberately chose not to. A comment saying that "no clobbers are needed" works even better (assuming they aren't).

2) Extended asm treats '%' as an token marker (rather like printf). If your basic asm string includes '%' characters, you will need to escape them using '%%' (for example asm("mov $0, %eax") becomes asm("mov $0, %%eax" : : :);).

3) On platforms that support dialects (including i386, pa, pdp11, rs6000, sh): The '{' '|' and '}' characters all have special meaning (see Multiple assembler dialects in asm templates). They will need to be escaped using '%{', '%|' or '%}' (for example, asm("mov '{', %al") becomes asm("mov '%{', %%al" : : :);).

For correctly written basic asm, that should be all that's needed.

Converting incorrect code

Note that for incorrectly written asm (which is very easy to do), you may need to do more work. For example, consider this MIPS code:

   asm ("sync");

In a compiler that clobbers memory for asm statements, this would work correctly. However since gcc's basic asm doesn't clobber memory, it needs to be written something like this:

   asm ("sync" : : : "memory");

For another example, consider this ARM code:

   __asm__ __volatile__ (
      "mov r0, #0x00\n\t"
      "vmsr fpscr, r0");

The code changes the r0 register without notifying the compiler. While this might be safe in some C compilers, it is incorrect for gcc. Consider one of these alternatives:

   /* Clobber the register. */
   __asm__ __volatile__ (
      "mov r0, #0x00\n\t"
      "vmsr fpscr, r0": : : "r0");

   /* Let GCC pick a register AND init it. */
   __asm__ __volatile__ (
      "vmsr fpscr, %0\n\t", ::"r"(0));

   /* Don't use asm at all. */
   __builtin_sh_set_fpscr(0);

Misc

Some unusual cases:

None: ConvertBasicAsmToExtended (last edited 2016-03-27 19:23:15 by ManuelLopezIbanez)