Basic Asm 2
Basic Asm 2
With extended asm you can read and write C variables from assembler and perform jumps from
assembler code to C labels. Extended asm syntax uses colons (‘:’) to delimit the operand
parameters after the assembler template:
where in the last form, asm-qualifiers contains goto (and in the first form, not).
The asm keyword is a GNU extension. When writing code that can be compiled with -ansi and
the various -std options, use __asm__ instead of asm (see Alternate Keywords).
Qualifiers
volatile
The typical use of extended asm statements is to manipulate input values to produce output
values. However, your asm statements may also produce side effects. If so, you may need to
use the volatile qualifier to disable certain optimizations. See Volatile.
inline
If you use the inline qualifier, then for inlining purposes the size of the asm statement is
taken as the smallest size possible (see Size of an asm).
goto
This qualifier informs the compiler that the asm statement may perform a jump to one of the
labels listed in the GotoLabels. See GotoLabels.
Parameters
AssemblerTemplate
This is a literal string that is the template for the assembler code. It is a combination of
fixed text and tokens that refer to the input, output, and goto parameters. See
AssemblerTemplate.
OutputOperands
InputOperands
Clobbers
GotoLabels
When you are using the goto form of asm, this section contains the list of all C labels to
which the code in the AssemblerTemplate may jump. See GotoLabels.
asm statements may not perform jumps into other asm statements, only to the listed
GotoLabels. GCC’s optimizers do not know about other jumps; therefore they cannot take
account of them when deciding how to optimize.
Remarks
The asm statement allows you to include assembly instructions directly within C code. This may
help you to maximize performance in time-sensitive code or to access assembly instructions that
are not readily available to C programs.
Similarly to basic asm, extended asm statements may be used both inside a C function or at file
scope (“top-level”), where you can use this technique to emit assembler directives, define
assembly language macros that can be invoked elsewhere in the file, or write entire functions in
assembly language. Extended asm statements outside of functions may not use any qualifiers, may
not specify clobbers, may not use %, + or & modifiers in constraints and can only use constraints
which don’t allow using any register.
Functions declared with the naked attribute require basic asm (see Common Attributes).
While the uses of asm are many and varied, it may help to think of an asm statement as a series of
low-level instructions that convert input parameters to output parameters. So a simple (if not
particularly useful) example for i386 using asm might look like this:
int src = 1;
int dst;
printf("%d\n", dst);
Volatile
Assembler Template
Output Operands
Flag Output Operands
Input Operands
Clobbers and Scratch Registers
Goto Labels
Generic Operand Modifiers
AArch64 Operand Modifiers
x86 Operand Modifiers
x86 Floating-Point asm Operands
MSP430 Operand Modifiers
LoongArch Operand Modifiers
RISC-V Operand Modifiers
SH Operand Modifiers
[Link] Volatile
GCC’s optimizers sometimes discard asm statements if they determine there is no need for the
output variables. Also, the optimizers may move code out of loops if they believe that the code
will always return the same result (i.e. none of its input values change between calls). Using the
volatile qualifier disables these optimizations. asm statements that have no output operands and
asm goto statements, are implicitly volatile.
This i386 code demonstrates a case that does not use (or require) the volatile qualifier. If it is
performing assertion checking, this code uses asm to perform the validation. Otherwise, dwRes is
unreferenced by any code. As a result, the optimizers can discard the asm statement, which in turn
removes the need for the entire DoCheck routine. By omitting the volatile qualifier when it isn’t
needed you allow the optimizers to produce the most efficient code possible.
The next example shows a case where the optimizers can recognize that the input (dwSomeValue)
never changes during the execution of the function and can therefore move the asm outside the
loop to produce more efficient code. Again, using the volatile qualifier disables this type of
optimization.
The following example demonstrates a case where you need to use the volatile qualifier. It uses
the x86 rdtsc instruction, which reads the computer’s time-stamp counter. Without the volatile
qualifier, the optimizers might assume that the asm block will always return the same value and
therefore optimize away the second call.
uint64_t msr;
// Do other work...
// Reprint the timestamp
asm volatile ( "rdtsc\n\t" // Returns the time in EDX:EAX.
"shl $32, %%rdx\n\t" // Shift the upper bits left.
"or %%rdx, %0" // 'Or' in the lower bits.
: "=a" (msr)
:
: "rdx");
GCC’s optimizers do not treat this code like the non-volatile code in the earlier examples. They
do not move it out of loops or omit it on the assumption that the result from a previous call is still
valid.
Note that the compiler can move even volatile asm instructions relative to other code, including
across jump instructions. For example, on many targets there is a system register that controls the
rounding mode of floating-point operations. Setting it with a volatile asm statement, as in the
following PowerPC example, does not work reliably.
The compiler may move the addition back before the volatile asm statement. To make it work as
expected, add an artificial dependency to the asm by referencing a variable in the subsequent
code, for example:
Under certain circumstances, GCC may duplicate (or remove duplicates of) your assembly code
when optimizing. This can lead to unexpected duplicate symbol errors during compilation if your
asm code defines symbols or labels. Using ‘%=’ (see AssemblerTemplate) may help resolve this
problem.
An assembler template is a literal string containing assembler instructions. In C++ with -std=gnu+
+11 or later, the assembler template can also be a constant expression inside parentheses (see C+
+11 Constant Expressions instead of String Literals).
The compiler replaces tokens in the template that refer to inputs, outputs, and goto labels, and
then outputs the resulting string to the assembler. The string can contain any instructions
recognized by the assembler, including directives. GCC does not parse the assembler instructions
themselves and does not know what they mean or even whether they are valid assembler input.
However, it does count the statements (see Size of an asm).
You may place multiple assembler instructions together in a single asm string, separated by the
characters normally used in assembly code for the system. A combination that works in most
places is a newline to break the line, plus a tab character to move to the instruction field (written
as ‘\n\t’). Some assemblers allow semicolons as a line separator. However, note that some
assembler dialects use semicolons to start a comment.
Do not expect a sequence of asm statements to remain perfectly consecutive after compilation,
even when you are using the volatile qualifier. If certain instructions need to remain consecutive
in the output, put them in a single multi-instruction asm statement.
Accessing data from C programs without using input/output operands (such as by using global
symbols directly from the assembler template) may not work as expected. Similarly, calling
functions directly from an assembler template requires a detailed understanding of the target
assembler and ABI.
Since GCC does not parse the assembler template, it has no visibility of any symbols it
references. This may result in GCC discarding those symbols as unreferenced unless they are also
listed as input, output, or goto operands.
In addition to the tokens described by the input, output, and goto operands, these tokens have
special meanings in the assembler template:
‘%%’
‘%=’
Outputs a number that is unique to each instance of the asm statement in the entire
compilation. This option is useful when creating local labels and referring to them multiple
times in a single template that generates multiple assembler instructions.
‘%{’
‘%|’
‘%}’
Outputs ‘{’, ‘|’, and ‘}’ characters (respectively) into the assembler code. When unescaped,
these characters have special meaning to indicate multiple assembler dialects, as described
below.
On targets such as x86, GCC supports multiple assembler dialects. The -masm option controls
which dialect GCC uses as its default for inline assembler. The target-specific documentation for
the -masm option contains the list of supported dialects, as well as the default dialect if the option
is not specified. This information may be important to understand, since assembler code that
works correctly when compiled using one dialect will likely fail if compiled using another. See
x86 Options.
If your code needs to support multiple assembler dialects (for example, if you are writing public
headers that need to support a variety of compilation options), use constructs of this form:
This construct outputs dialect0 when using dialect #0 to compile the code, dialect1 for dialect
#1, etc. If there are fewer alternatives within the braces than the number of dialects the compiler
supports, the construct outputs nothing.
For example, if an x86 compiler supports two dialects (‘att’, ‘intel’), an assembler template
such as this:
is equivalent to one of
"xchg{l}\t{%%}ebx, %1"
corresponds to either
An asm statement has zero or more output operands indicating the names of C variables modified
by the assembler code.
In this i386 example, old (referred to in the template string as %0) and *Base (as %1) are outputs
and Offset (%2) is an input:
bool old;
return old;
asmSymbolicName
Specifies an optional symbolic name for the operand. The literal square brackets ‘[]’
around the asmSymbolicName are required both in the operand specification and references
to the operand in the assembler template, i.e. ‘%[Value]’. The scope of the name is the asm
statement that contains the definition. Any valid C identifier is acceptable, including names
already defined in the surrounding code. No two operands within the same asm statement
can use the same symbolic name.
When not using an asmSymbolicName, use the (zero-based) position of the operand in the
list of operands in the assembler template. For example if there are three output operands,
use ‘%0’ in the template to refer to the first, ‘%1’ for the second, and ‘%2’ for the third.
constraint
A string constant specifying constraints on the placement of the operand; See Constraints
for asm Operands, for details. In C++ with -std=gnu++11 or later, the constraint can also be
a constant expression inside parentheses (see C++11 Constant Expressions instead of String
Literals).
Output constraints must begin with either ‘=’ (a variable overwriting an existing value) or
‘+’ (when reading and writing). When using ‘=’, do not assume the location contains the
existing value on entry to the asm, except when the operand is tied to an input; see Input
Operands.
After the prefix, there must be one or more additional constraints (see Constraints for asm
Operands) that describe where the value resides. Common constraints include ‘r’ for
register and ‘m’ for memory. When you list more than one possible location (for example,
"=rm"), the compiler chooses the most efficient one based on the current context. If you list
as many alternates as the asm statement allows, you permit the optimizers to produce the
best possible code. If you must use a specific register, but your Machine Constraints do not
provide sufficient control to select the specific register you want, local register variables
may provide a solution (see Specifying Registers for Local Variables).
cvariablename
Specifies a C lvalue expression to hold the output, typically a variable name. The enclosing
parentheses are a required part of the syntax.
When the compiler selects the registers to use to represent the output operands, it does not use
any of the clobbered registers (see Clobbers and Scratch Registers).
Output operand expressions must be lvalues. The compiler cannot check whether the operands
have data types that are reasonable for the instruction being executed. For output expressions that
are not directly addressable (for example a bit-field), the constraint must allow a register. In that
case, GCC uses the register as the output of the asm, and then stores that register into the output.
Operands using the ‘+’ constraint modifier count as two operands (that is, both as input and
output) towards the total maximum of 30 operands per asm statement.
Use the ‘&’ constraint modifier (see Constraint Modifier Characters) on all output operands that
must not overlap an input. Otherwise, GCC may allocate the output operand in the same register
as an unrelated input operand, on the assumption that the assembler code consumes its inputs
before producing outputs. This assumption may be false if the assembler code actually consists of
more than one instruction.
The same problem can occur if one output parameter (a) allows a register constraint and another
output parameter (b) allows a memory constraint. The code generated by GCC to access the
memory address in b can contain registers which might be shared by a, and GCC considers those
registers to be inputs to the asm. As above, GCC assumes that such input registers are consumed
before any outputs are written. This assumption may result in incorrect behavior if the asm
statement writes to a before using b. Combining the ‘&’ modifier with the register constraint on a
ensures that modifying a does not affect the address referenced by b. Otherwise, the location of b
is undefined if a is modified before using b.
asm supports operand modifiers on operands (for example ‘%k2’ instead of simply ‘%2’). Generic
Operand modifiers lists the modifiers that are available on all targets. Other modifiers are
hardware dependent. For example, the list of supported modifiers for x86 is found at x86
Operand modifiers.
If the C code that follows the asm makes no use of any of the output operands, use volatile for
the asm statement to prevent the optimizers from discarding the asm statement as unneeded (see
Volatile).
This code makes no use of the optional asmSymbolicName. Therefore it references the first
output operand as %0 (were there a second, it would be %1, etc). The number of the first input
operand is one greater than that of the last output operand. In this i386 example, that makes Mask
referenced as %1:
uint32_t Mask = 1234;
uint32_t Index;
That code overwrites the variable Index (‘=’), placing the value in a register (‘r’). Using the
generic ‘r’ constraint instead of a constraint for a specific register allows the compiler to pick the
register to use, which can result in more efficient code. This may not be possible if an assembler
instruction requires a specific register.
The following i386 example uses the asmSymbolicName syntax. It produces the same result as
the code above, but some may consider it more readable or more maintainable since reordering
index numbers is not necessary when adding or removing operands. The names aIndex and aMask
are only used in this example to emphasize which names get used where. It is acceptable to reuse
the names Index and Mask.
uint32_t c = 1;
uint32_t d;
uint32_t *e = &c;
Here, d may either be in a register or in memory. Since the compiler might already have the
current value of the uint32_t location pointed to by e in a register, you can enable it to choose the
best location for d by specifying both constraints.
Some targets have a special register that holds the “flags” for the result of an operation or
comparison. Normally, the contents of that register are either unmodified by the asm, or the asm
statement is considered to clobber the contents.
On some targets, a special form of output operand exists by which conditions in the flags register
may be outputs of the asm. The set of conditions supported are target specific, but the general rule
is that the output variable must be a scalar integer, and the value is boolean. When supported, the
target defines the preprocessor symbol __GCC_ASM_FLAG_OUTPUTS__.
Because of the special nature of the flag output operands, the constraint may not include
alternatives.
Most often, the target has only one flags register, and thus is an implied operand of many
instructions. In this case, the operand should not be referenced within the assembler template via
%0 etc, as there’s no corresponding text in the assembly language.
ARM
AArch64
The flag output constraints for the ARM family are of the form ‘=@cccond’ where cond is
one of the standard conditions defined in the ARM ARM for ConditionHolds.
eq
ne
cs
hs
cc
lo
mi
pl
vs
vc
V flag clear
hi
ls
ge
lt
gt
le
x86 family
The flag output constraints for the x86 family are of the form ‘=@cccond’ where cond is one
of the standard conditions defined in the ISA manual for jcc or setcc.
ae
be
c
carry flag set
e
z
ge
le
na
nae
nb
nbe
nc
ne
ng
nge
nl
nle
no
np
ns
nz
s390
The flag output constraint for s390 is ‘=@cc’. Only one such constraint is allowed. The
variable has to be stored in a ‘int’ variable.
Input operands make values from C variables and expressions available to the assembly code.
asmSymbolicName
Specifies an optional symbolic name for the operand. The literal square brackets ‘[]’
around the asmSymbolicName are required both in the operand specification and references
to the operand in the assembler template, i.e. ‘%[Value]’. The scope of the name is the asm
statement that contains the definition. Any valid C identifier is acceptable, including names
already defined in the surrounding code. No two operands within the same asm statement
can use the same symbolic name.
When not using an asmSymbolicName, use the (zero-based) position of the operand in the
list of operands in the assembler template. For example if there are two output operands
and three inputs, use ‘%2’ in the template to refer to the first input operand, ‘%3’ for the
second, and ‘%4’ for the third.
constraint
A string constant specifying constraints on the placement of the operand; See Constraints
for asm Operands, for details. In C++ with -std=gnu++11 or later, the constraint can also be
a constant expression inside parentheses (see C++11 Constant Expressions instead of String
Literals).
Input constraint strings may not begin with either ‘=’ or ‘+’. When you list more than one
possible location (for example, ‘"irm"’), the compiler chooses the most efficient one based
on the current context. If you must use a specific register, but your Machine Constraints do
not provide sufficient control to select the specific register you want, local register
variables may provide a solution (see Specifying Registers for Local Variables).
Input constraints can also be digits (for example, "0"). This indicates that the specified
input must be in the same place as the output constraint at the (zero-based) index in the
output constraint list. When using asmSymbolicName syntax for the output operands, you
may use these names (enclosed in brackets ‘[]’) instead of digits.
cexpression
This is the C variable or expression being passed to the asm statement as input. The
enclosing parentheses are a required part of the syntax.
When the compiler selects the registers to use to represent the input operands, it does not use any
of the clobbered registers (see Clobbers and Scratch Registers).
If there are no output operands but there are input operands, place two consecutive colons where
the output operands would go:
Warning: Do not modify the contents of input-only operands (except for inputs tied to outputs).
The compiler assumes that on exit from the asm statement these operands contain the same values
as they had before executing the statement. It is not possible to use clobbers to inform the
compiler that the values in these inputs are changing. One common work-around is to tie the
changing input variable to an output variable that never gets used. Note, however, that if the code
that follows the asm statement makes no use of any of the output operands, the GCC optimizers
may discard the asm statement as unneeded (see Volatile).
asm supports operand modifiers on operands (for example ‘%k2’ instead of simply ‘%2’). Generic
Operand modifiers lists the modifiers that are available on all targets. Other modifiers are
hardware dependent. For example, the list of supported modifiers for x86 is found at x86
Operand modifiers.
In this example using the fictitious combine instruction, the constraint "0" for input operand 1 says
that it must occupy the same location as output operand 0. Only input operands may use numbers
in constraints, and they must each refer to an output operand. Only a number (or the symbolic
assembler name) in the constraint can guarantee that one operand is in the same place as another.
The mere fact that foo is the value of both operands is not enough to guarantee that they are in the
same place in the generated assembler code.
While the compiler is aware of changes to entries listed in the output operands, the inline asm
code may modify more than just the outputs. For example, calculations may require additional
registers, or the processor may overwrite a register as a side effect of a particular assembler
instruction. In order to inform the compiler of these changes, list them in the clobber list. Clobber
list items are either register names or the special clobbers (listed below). Each clobber list item is
a string constant enclosed in double quotes and separated by commas. In C++ with -std=gnu++11
or later, a clobber list item can also be a constant expression inside parentheses (see C++11
Constant Expressions instead of String Literals).
Clobber descriptions may not in any way overlap with an input or output operand. For example,
you may not have an operand describing a register class with one member when listing that
register in the clobber list. Variables declared to live in specific registers (see Variables in
Specified Registers) and used as asm input or output operands must have no part mentioned in the
clobber description. In particular, there is no way to specify that input operands get modified
without also specifying them as output operands.
When the compiler selects which registers to use to represent input and output operands, it does
not use any of the clobbered registers. As a result, clobbered registers are available for any use in
the assembler code.
Another restriction is that the clobber list should not contain the stack pointer register. This is
because the compiler requires the value of the stack pointer to be the same after an asm statement
as it was on entry to the statement. However, previous versions of GCC did not enforce this rule
and allowed the stack pointer to appear in the list, with unclear semantics. This behavior is
deprecated and listing the stack pointer may become an error in future versions of GCC.
Here is a realistic example for the VAX showing the use of clobbered registers:
"cc"
The "cc" clobber indicates that the assembler code modifies the flags register. On some
machines, GCC represents the condition codes as a specific hardware register; "cc" serves
to name this register. On other machines, condition code handling is different, and
specifying "cc" has no effect. But it is valid no matter what the target.
"memory"
The "memory" clobber tells the compiler that the assembly code performs memory reads or
writes to items other than those listed in the input and output operands (for example,
accessing the memory pointed to by one of the input parameters). To ensure memory
contains correct values, GCC may need to flush specific register values to memory before
executing the asm. Further, the compiler does not assume that any values read from memory
before an asm remain unchanged after that asm; it reloads them as needed. Using the
"memory" clobber effectively forms a read/write memory barrier for the compiler.
Note that this clobber does not prevent the processor from doing speculative reads past the
asm statement. To prevent that, you need processor-specific fence instructions.
"redzone"
The "redzone" clobber tells the compiler that the assembly code may write to the stack red
zone, area below the stack pointer which on some architectures in some calling conventions
is guaranteed not to be changed by signal handlers, interrupts or exceptions and so the
compiler can store there temporaries in leaf functions. On targets which have no concept of
the stack red zone, the clobber is ignored. It should be used e.g. in case the assembly code
uses call instructions or pushes something to the stack without taking the red zone into
account by subtracting red zone size from the stack pointer first and restoring it afterwards.
Flushing registers to memory has performance implications and may be an issue for time-
sensitive code. You can provide better information to GCC to avoid this, as shown in the
following examples. At a minimum, aliasing rules allow GCC to know what memory doesn’t
need to be flushed.
Here is a fictitious sum of squares instruction, that takes two pointers to floating point values in
memory and produces a floating point register output. Notice that x, and y both appear twice in
the asm parameters, once to specify memory accessed, and once to specify a base register used by
the asm. You won’t normally be wasting a register by doing this as GCC can use the same register
for both purposes. However, it would be foolish to use both %1 and %3 for x in this asm and expect
them to be the same. In fact, %3 may well not be a register. It might be a symbolic memory
reference to the object pointed to by x.
Here is a fictitious *z++ = *x++ * *y++ instruction. Notice that the x, y and z pointer registers
must be specified as input/output because the asm modifies them.
asm ("vecmul %0, %1, %2"
: "+r" (z), "+r" (x), "+r" (y), "=m" (*z)
: "m" (*x), "m" (*y));
asm("repne scasb"
: "=c" (count), "+D" (p)
: "m" (*(const char (*)[]) p), "0" (-1), "a" (0));
If you know the above will only be reading a ten byte array then you could instead use a memory
input like: "m" (*(const char (*)[10]) p).
Here is an example of a PowerPC vector scale implemented in assembly, complete with vector
and condition code clobbers, and some initialized offset registers that are unchanged by the asm.
void
dscal (size_t n, double *x, double alpha)
{
asm ("/* lots of asm here */"
: "+m" (*(double (*)[n]) x), "+&r" (n), "+b" (x)
: "d" (alpha), "b" (32), "b" (48), "b" (64),
"b" (80), "b" (96), "b" (112)
: "cr0",
"vs32","vs33","vs34","vs35","vs36","vs37","vs38","vs39",
"vs40","vs41","vs42","vs43","vs44","vs45","vs46","vs47");
}
Rather than allocating fixed registers via clobbers to provide scratch registers for an asm
statement, an alternative is to define a variable and make it an early-clobber output as with a2 and
a3 in the example below. This gives the compiler register allocator more freedom. You can also
define a variable and make it an output tied to an input as with a0 and a1, tied respectively to ap
and lda. Of course, with tied outputs your asm can’t use the input value after modifying the output
register since they are one and the same register. What’s more, if you omit the early-clobber on
the output, it is possible that GCC might allocate the same register to another of the inputs if
GCC could prove they had the same value on entry to the asm. This is why a1 has an early-
clobber. Its tied input, lda might conceivably be known to have the value 16 and without an
early-clobber share the same register as %11. On the other hand, ap can’t be the same as any of the
other inputs, so an early-clobber on a0 is not needed. It is also not desirable in this case. An early-
clobber on a0 would cause GCC to allocate a separate register for the "m" (*(const double (*)
[]) ap) input. Note that tying an input to an output is the way to set up an initialized temporary
register modified by an asm statement. An input not tied to an output is assumed by GCC to be
unchanged, for example "b" (16) below sets up %11 to 16, and GCC might use that register in
following code if the value 16 happened to be needed. You can even use a normal asm output for a
scratch if all inputs that might share the same register are consumed before the scratch is used.
The VSX registers clobbered by the asm statement could have used this technique except for
GCC’s limit on the number of asm parameters.
static void
dgemv_kernel_4x4 (long n, const double *ap, long lda,
const double *x, double *y, double alpha)
{
double *a0;
double *a1;
double *a2;
double *a3;
__asm__
(
/* lots of asm here */
"#n=%1 ap=%8=%12 lda=%13 x=%7=%10 y=%0=%2 alpha=%9 o16=%11\n"
"#a0=%3 a1=%4 a2=%5 a3=%6"
:
"+m" (*(double (*)[n]) y),
"+&r" (n), // 1
"+b" (y), // 2
"=b" (a0), // 3
"=&b" (a1), // 4
"=&b" (a2), // 5
"=&b" (a3) // 6
:
"m" (*(const double (*)[n]) x),
"m" (*(const double (*)[]) ap),
"d" (alpha), // 9
"r" (x), // 10
"b" (16), // 11
"3" (ap), // 12
"4" (lda) // 13
:
"cr0",
"vs32","vs33","vs34","vs35","vs36","vs37",
"vs40","vs41","vs42","vs43","vs44","vs45","vs46","vs47"
);
}
asm goto allows assembly code to jump to one or more C labels. The GotoLabels section in an
asm goto statement contains a comma-separated list of all C labels to which the assembler code
may jump. GCC assumes that asm execution falls through to the next statement (if this is not the
case, consider using the __builtin_unreachable intrinsic after the asm statement). Optimization of
asm goto may be improved by using the hot and cold label attributes (see Common Attributes).
If the assembler code does modify anything, use the "memory" clobber to force the optimizers to
flush all register values to memory and reload them if necessary after the asm statement.
Also note that an asm goto statement is always implicitly considered volatile.
Be careful when you set output operands inside asm goto only on some possible control flow
paths. If you don’t set up the output on given path and never use it on this path, it is okay.
Otherwise, you should use ‘+’ constraint modifier meaning that the operand is input and output
one. With this modifier you will have the correct values on all possible paths from the asm goto.
To reference a label in the assembler template, prefix it with ‘%l’ (lowercase ‘L’) followed by its
(zero-based) position in GotoLabels plus the number of input and output operands. Output
operand with constraint modifier ‘+’ is counted as two operands because it is considered as one
output and one input operand. For example, if the asm has three inputs, one output operand with
constraint modifier ‘+’ and one output operand with constraint modifier ‘=’ and references two
labels, refer to the first label as ‘%l6’ and the second as ‘%l7’).
Alternately, you can reference labels using the actual C label name enclosed in brackets. For
example, to reference a label named carry, you can use ‘%l[carry]’. The label must still be listed
in the GotoLabels section when using this approach. It is better to use the named references for
labels as in this case you can avoid counting input and output operands and special treatment of
output operands with constraint modifier ‘+’.
asm goto (
"btl %1, %0\n\t"
"jc %l2"
: /* No outputs. */
: "r" (p1), "r" (p2)
: "cc"
: carry);
return 0;
carry:
return 1;
The following example shows an asm goto that uses a memory clobber.
int frob(int x)
{
int y;
asm goto ("frob %%r5, %1; jc %l[error]; mov (%2), %%r5"
: /* No outputs. */
: "r"(x), "r"(&y)
: "r5", "memory"
: error);
return y;
error:
return -1;
}
The following artificial example shows an asm goto that sets up an output only on one path inside
the asm goto. Usage of constraint modifier ‘=’ instead of ‘+’ would be wrong as factor is used on
all paths from the asm goto.
The following table shows the modifiers supported by all targets and their effects:
The following table shows the modifiers supported by AArch64 and their effects:
Modifier Description
Print a 32-bit general-purpose register name or, given a constant zero operand, the 32-
w
bit zero register (wzr).
Print a 64-bit general-purpose register name or, given a constant zero operand, the 64-
x
bit zero register (xzr).
b Print an FP/SIMD register name with a b (byte, 8-bit) prefix.
h Print an FP/SIMD register name with an h (halfword, 16-bit) prefix.
s Print an FP/SIMD register name with an s (single word, 32-bit) prefix.
d Print an FP/SIMD register name with a d (doubleword, 64-bit) prefix.
q Print an FP/SIMD register name with a q (quadword, 128-bit) prefix.
Print an FP/SIMD register name as an SVE register (i.e. with a z prefix). This is a no-
Z
op for SVE register operands.
References to input, output, and goto operands in the assembler template of extended asm
statements can use modifiers to affect the way the operands are formatted in the code output to
the assembler. For example, the following code uses the ‘h’ and ‘b’ modifiers for x86:
uint16_t num;
asm volatile ("xchg %h0, %b0" : "+a" (num) );
The rest of this discussion uses the following code for illustrative purposes.
int main()
{
int iInt = 1;
top:
With no modifiers, this is what the output from the operands would be for the ‘att’ and ‘intel’
dialects of assembler:
%1 $2 2
The table below shows the list of supported modifiers and their effects.
Print the opcode suffix for the size of the current integer
z %z0 l
operand (one of b/w/l/q).
V is a special modifier which prints the name of the full integer register without %.
On x86 targets, there are several rules on the usage of stack-like registers in the operands of an
asm. These rules apply only to the operands that are stack-like registers:
1. Given a set of input registers that die in an asm, it is necessary to know which are implicitly
popped by the asm, and which must be explicitly popped by GCC.
An input register that is implicitly popped by the asm must be explicitly clobbered, unless it
is constrained to match an output operand.
2. For any input register that is implicitly popped by an asm, it is necessary to know how to
adjust the stack to compensate for the pop. If any non-popped input is closer to the top of
the reg-stack than the implicitly popped register, it would not be possible to know what the
stack looked like—it’s not clear how the rest of the stack “slides up”.
All implicitly popped input registers must be closer to the top of the reg-stack than any
input that is not implicitly popped.
It is possible that if an input dies in an asm, the compiler might use the input register for an
output reload. Consider this example:
To prevent this from happening, if any input operand uses the ‘f’ constraint, all output
register constraints must use the ‘&’ early-clobber modifier.
3. Some operands need to be in particular places on the stack. All output operands fall in this
category—GCC has no other way to know which registers the outputs appear in unless you
indicate this in the constraints.
Output operands must specifically indicate which register an output appears in after an asm.
‘=f’ is not allowed: the operand constraints must select a class with a single register.
4. Output operands may not be “inserted” between existing stack registers. Since no 387
opcode uses a read/write operand, all output operands are dead before the asm, and are
pushed by the asm. It makes no sense to push anywhere but the top of the reg-stack.
Output operands must start at the top of the reg-stack: output operands may not “skip” a
register.
5. Some asm statements may need extra stack space for internal calculations. This can be
guaranteed by clobbering stack registers unrelated to the inputs and outputs.
This asm takes one input, which is internally popped, and produces two outputs.
This asm takes two inputs, which are popped by the fyl2xp1 opcode, and replaces them with one
output. The st(1) clobber is necessary for the compiler to know that fyl2xp1 pops both inputs.
The list below describes the supported modifiers and their effects for MSP430.
Modifier Description
A Select low 16-bits of the constant/register/memory operand.
B Select high 16-bits of the constant/register/memory operand.
Modifier Description
C Select bits 32-47 of the constant/register/memory operand.
D Select bits 48-63 of the constant/register/memory operand.
H Equivalent to B (for backwards compatibility).
I Print the inverse (logical NOT) of the constant value.
J Print an integer without a # prefix.
L Equivalent to A (for backwards compatibility).
O Offset of the current frame from the top of the stack.
Q Use the A instruction postfix.
R Inverse of condition code, for unsigned comparisons.
W Subtract 16 from the constant value.
X Use the X instruction postfix.
Y Subtract 4 from the constant value.
Z Subtract 1 from the constant value.
b Append .B, .W or .A to the instruction, depending on the mode.
d Offset 1 byte of a memory reference or constant value.
e Offset 3 bytes of a memory reference or constant value.
f Offset 5 bytes of a memory reference or constant value.
g Offset 7 bytes of a memory reference or constant value.
Print the value of 2, raised to the power of the given constant. Used to select the
p
specified bit position.
r Inverse of condition code, for signed comparisons.
x Equivalent to X, but only for pointers.
The list below describes the supported modifiers and their effects for LoongArch.
Modifier Description
d Same as c.
i Print the character ”i” if the operand is not a register.
m Same as c, but the printed value is operand - 1.
u Print a LASX register.
Modifier Description
w Print a LSX register.
X Print a constant integer operand in hexadecimal.
z Print the operand in its unmodified form, followed by a comma.
References to input and output operands in the assembler template of extended asm statements
can use modifiers to affect the way the operands are formatted in the code output to the
assembler. For example, the following code uses the ’w’ modifier for LoongArch:
test-asm.c:
#include <lsxintrin.h>
return c;
}
vadd.d $vr0,$vr0,$vr1
This is a 128-bit vector addition instruction, c (referred to in the template string as %0) is the
output, and a (%1) and b (%2) are the inputs. __m128i is a vector data type defined in the file
lsxintrin.h (See LoongArch SX Vector Intrinsics). The symbol ’=f’ represents a constraint using
a floating-point register as an output type, and the ’f’ in the input operand represents a constraint
using a floating-point register operand, which can refer to the definition of a constraint (See
Constraints for asm Operands) in gcc.
The list below describes the supported modifiers and their effects for RISC-V.
Modifier Description
Modifier Description
z Print ”zero” instead of 0 if the operand is an immediate with a value of zero.
i Print the character ”i” if the operand is an immediate.
N Print the register encoding as integer (0 - 31).
H Print the name of the next register for integer.
The list below describes the supported modifiers and their effects for the SH family of processors.
Modifier Description
. Print ”.s” if the instruction needs a delay slot.
, Print ”LOCAL_LABEL_PREFIX”.
@ Print ”trap”, ”rte” or ”rts” depending on the interrupt pragma used.
# Print ”nop” if there is nothing to put in the delay slot.
' Print likelihood suffix (”/u” for unlikely).
> Print branch target if ”-fverbose-asm”.
O Require a constant operand and print the constant expression with no punctuation.
R Print the ”LSW” of a dp value - changes if in little endian.
S Print the ”MSW” of a dp value - changes if in little endian.
T Print the next word of a dp value - same as ”R” in big endian mode.
M Print ”.b ”, ”.w”, ”.l”, ”.s”, ”.d”, suffix if operand is a MEM.
N Print ”r63” if the operand is ”const_int 0”.
d Print a ”V2SF” as ”dN” instead of ”fpN”.
m Print the pair ”base,offset” or ”base,index” for LD and ST.
U Like ”%m” for ”LD” and ”ST”, ”HI” and ”LO”.
V Print the position of a single bit set.
W Print the position of a single bit cleared.
t Print a memory address which is a register.
u Print the lowest 16 bits of ”CONST_INT”, as an unsigned value.
o Print an operator.
Next: Constraints for asm Operands, Previous: Basic Asm — Assembler Instructions Without
Operands, Up: How to Use Inline Assembly Language in C Code [Contents][Index]