With gnu++11 or later the string can also be a compile time constant expression
inside parens. The constant expression can return a string or a container
with data and size members, following similar rules as C++26 static_assert
message. Any string is converted to the character set of the source code.
When this feature is available the __GXX_CONSTEXPR_ASM__
cpp symbol is defined.
#include <string> constexpr std::string_view genfoo() { return "foo"; } void function() { asm((genfoo())); }
Using extended asm
(see Extended Asm - Assembler Instructions with C Expression Operands) typically produces
smaller, safer, and more efficient code, and in most cases it is a
better solution than basic asm
. However, functions declared
with the naked
attribute require only basic asm
(see Declaring Attributes of Functions).
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.
Safely accessing C data and calling functions from basic asm
is more
complex than it may appear. To access C data, it is better to use extended
asm
.
Do not expect a sequence of asm
statements to remain perfectly
consecutive after compilation. If certain instructions need to remain
consecutive in the output, put them in a single multi-instruction asm
statement. Note that GCC’s optimizers can move asm
statements
relative to other code, including across jumps.
asm
statements may not perform jumps into other asm
statements.
GCC does not know about these jumps, and therefore cannot take
account of them when deciding how to optimize. Jumps from asm
to C
labels are only supported in extended asm
.
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 assembly code defines symbols or labels.
Warning: The C standards do not specify semantics for asm
,
making it a potential source of incompatibilities between compilers. These
incompatibilities may not produce compiler warnings/errors.
GCC does not parse basic asm
’s AssemblerInstructions, which
means there is no way to communicate to the compiler what is happening
inside them. GCC has no visibility of symbols in the asm
and may
discard them as unreferenced. It also does not know about side effects of
the assembler code, such as modifications to memory or registers. Unlike
some compilers, GCC assumes that no changes to general purpose registers
occur. This assumption may change in a future release.
To avoid complications from future changes to the semantics and the
compatibility issues between compilers, consider replacing basic asm
with extended asm
. See
How to convert
from basic asm to extended asm for information about how to perform this
conversion.
The compiler copies the assembler instructions in a basic asm
verbatim to the assembly language output file, without
processing dialects or any of the ‘%’ operators that are available with
extended asm
. This results in minor differences between basic
asm
strings and extended asm
templates. For example, to refer to
registers you might use ‘%eax’ in basic asm
and
‘%%eax’ in extended asm
.
On targets such as x86 that support multiple assembler dialects,
all basic asm
blocks use the assembler dialect specified by the
-masm command-line option (see x86 Options).
Basic asm
provides no
mechanism to provide different assembler strings for different dialects.
For basic asm
with non-empty assembler string GCC assumes
the assembler block does not change any general purpose registers,
but it may read or write any globally accessible variable.
Here is an example of basic asm
for i386:
/* Note that this code will not compile with -masm=intel */ #define DebugBreak() asm("int $3")