Date: Feb 24, 2005

All of the notes that follow apply to the 386 architecture. 

info gcc : Section : C Extensions : Extended Asm

Some notes : 
The embedded gcc consists of 4 components, separated by colons (:). 
<assembler_instruction_template> 
: <output_operands> 
: <input_operands> 
: <something_about clobbering> 

Let us keep the 4th section out for now, so considering the first three sections, a sample asm instruction could be written as :

__asm__ __volatile__(
"lock; addl %1,%0"
:"=m" (var)
:"ir" (i), "m" (var));
{ Simplified from include/asm-i386/atomic.h : atomic_add }
  1. Assembler Instruction Template
    This contains all the assembly instructions that you want to include. The instructions are written in the format as you would write for the corresponding assembler.

    Generally, newlines (“\n”) are used to separate each statement. Tabs (“\t”) take you to the column where you write the instructions. Whereas, labels start immediately after the newline. The instructions in this section may reference operands from the input and output operands section. The ‘n’th operand could be referenced as %n. (0th by %0, 1st by %1).

  2. Output Operands Section
    This section includes the set of output operands. Each operand is separated by commas. The first operand in the list is termed as the “0th” operand. The rest of the operands are numbered sequentially. The numbers keep going even into the input operands section.You can directly use C expressions in the input/output operands section. That gives you a lot of flexibility, since you need not know, which registers the C variables are stored in. The operands are listed in the following format : “<constraints>”(<C expression>)

    In the sample code shown above, “=m” are the constraints, and “var” is the C variable being used.

    The “=” indicates that this is an output operand. All output operands should have “=” as one of the constraints. (The “=” appears to be redundant though, since you are already writing it in the output operands section.)

    “m” is another constraint which indicates that the operand is stored in memory. “r” indicates that it is stored in a register. More on constraints later in the document.

  3. Input Operands Section
    Input operands could be written similarly to the output operands as “<constraints>”(C expression)

Now looking at the asm code above, it is clear that “i” (%1) is being added to the variable “var” (%0), with the CPU lock held.
Some Other notes : 

  • Gcc does strange things to optimise code, which may actually cause unexpected things to happen. Precautions should be taken to avoid this. (volatile, among others)
  • Generally, output operands are treated as write-only. Read-write operands should be handled specially. “+” is used to indicate this operand (e.g. include/asm-i386/rwsem.h:down_read)

    For register operands, there is another way of doing this. If an operand occurs in the ‘n’th position in the output operands section then the input operand constraint can include “n” indicating that it shares space with the output operand number n. (e.g. include/asm-i386/string-486.h : __memcpy_g, n is same as d0, tmp is same as d1 and from is same as d2)

  • Local Labels can be used in the assembly code by means of numbers, like 0. The reference to these variables could be made as 0b (label 0 whose definition occurs behind this place) and 0f (label 0 whose definition occurs after this place). As can be deduced the same label could be defined multiple times.
  • “&” as an output operand constraint indicates that it should not be stored in a location where input operands lie. This is helpful in case of multiple instructions, where the input operands may be further used, even after this output operand is generated.
  • Constraints
    i = immediate integer operand. (one with a constant value) 
    F = immediate floating operand 
    g = any register, memory or immediate operand is allowed 
    f = floating point register