Inline Assembly |
Rules of Engagement
By Dylan Cuthbert
Last Updated: 8th July 2000
|This page attempts to list a
no. of rules to follow when using GCC's (Gnu
Compiler Collection) extended asm
feature. This feature is very powerful when used properly, and very
dangerous when used incorrectly. |
The basic format of the inline asm is:
asm( "cmd %0, %1, %2" : "=X" ( x ) : "Y" ( y ), "Z" ( z ) : "R1", "R2", "R3" );
The statement consists of four parts separated by colons. The first part is the asm statement itself which is described by a string literal. This string is a template and by using "%", operands or information from the compiler can be inserted in a similar way to printf. For example, %5 will insert operand 5 (or the sixth operand as counting begins at 0). %= will insert a unique number useful for generating labels.
The second and third sections of the statement describe the operands the asm statement needs. The second section describes the outputs (write-only or read/write), and the third section describes the inputs (read-only). They consist of a comma separated list of a string literal describing the operand constraint, and in brackets, the operand itself. The string is called an operand constraint. Click the link for an exhaustive list of constraints and explanations.
The most common constraints are "r" ("=r") and "m" ("=m"). "r" tells the compiler that the asm statement requires an integer register to hold the variable (use "f" to specify floating point registers). "m" tells the compiler that the asm statement requires a memory address pointing to the variable. Note, however, the variable specification doesn't change, ie. don't use '"m" (&var)' as that will give you the address of the address of the variable in question.
The fourth section of the statement are what GCC refers to as "clobbers". This list specifies the "side-effects" of the asm statement that the compiler can't see. For example, if the asm statement *must* at all costs write to register $6 then you must specify "$6" in the clobber list. Also, if you write to memory that hasn't been specified with the "=m" or "+m" operand constraint you must specify the special keyword "memory" in the clobber list. Don't use the "memory" clobber specification lightly though, as it requires the compiler to save all register-loaded values immediately before the asm statement. In almost every case "=m" or "+m" should suffice.
(please bear in mind, this is most definitely not an exhaustive or even close to definitive guide and is intended, simply, to be a quick brush-up of the essentials. For further reading also try GCC's guide and DJGPP's couple of guides which are i386 oriented but still very useful)
|1. Never write to an
input argument. Bear in mind an input argument is any argument
within the third ':' delimited section of the asm statement. |
2. Never read from an "=r"/"=m" (ie. output) operand (unless you have already modified it).
3. Never read from an input operand *after* you have written to an output operand (the compiler often optimally uses the same register or memory location). If you need to do this use the "=&r" or "=&m" constraint which tells the compiler the output must be unaliased and therefore guarantees a different register/memory location to be supplied.
4. There is no no. 4.
5. If you write to memory that hasn't been specified with "=m" or "+m" then you must specify "memory" in the clobber list.
6. Never attempt to read or write more than the size of the operands specified, eg. if you use "=r" (val) where val is an int, and in the asm statement you perform, for example, (MIPS) an mfc1 (an operation affecting 64 bits), the compiler only thinks you've overwritten 32 bits and won't preserve the full values across function calls and the like.
7. Avoid clobbering arbitrary registers - in almost every case you can specify that you want to clobber a register by simply specifying an extra (albeit unused) output. The clobber list is intended primarily for asm instructions that have no choice as to which register they write to; often the case with Intel chips but rarely, if ever, the case with Motorola or Mips.
8. Follow these rules strictly, there is no gray area with regards to inline asm, you'll only invite upon yourself a world of hurt when the compiler decides to optimize things a little differently.