Cover image for GCC Inline Assembly

GCC Inline Assembly

Words 1.6k
Views
Visitors

Timeline

Timeline

2025-09-27

init

This article introduces two modes of GCC Inline Assembly: basic inline assembly and extended inline assembly. Basic inline assembly uses the asm keyword to embed assembly code as a string in C language, but GCC does not parse its content, and the optimizer may move instruction order. Extended inline assembly uses the asm keyword with qualifiers (volatile, inline, goto) and output operands, input operands, and clobbers to precisely control the interaction between assembly and C variables. The article details the constraints for output and input operands (e.g., '=' means write-only, '+' means read-write, 'r' means general-purpose register), and that clobbers are used to inform the compiler that registers, condition codes, or memory may be modified, thereby preventing the optimizer from reordering or caching variables. It also introduces operand numbering rules (starting from 0, outputs first then inputs), differences in constraint modifiers under ARM64, and methods for referencing variables via assembly symbolic names. In addition, the article demonstrates through experiments the use of inline assembly to implement memcpy, memset, atomic operations, system register read/write, and other functions, and explores advanced usage combined with macros, including

Reference documents:

Inline Assembly Language: embedding assembly code in C language

Purpose:

  • Optimization: optimize for specific time-sensitive code
  • C language needs to access certain special instructions to implement special functions, such as memory barrier instructions

Two modes of inline assembly

  • Basic inline assembly
  • Extended inline assembly

Basic inline assembly

Format:

1
asm asm-qualifiers(AssemblerInstructions)
  • asm keyword: indicates this is a GNU extension

  • Qualifiers

    • volatile: this qualifier is usually not needed in basic inline assembly
    • inline: inline, the asm assembly code will be as small as possible
  • Assembler instructions block

    • The GCC compiler treats inline assembly as a string

    • GCC compilation does not parse or analyze inline assembly

    • For multiple assembly instructions, you need to use “\n\t” to break lines

    • GCC’s optimizer can move assembly instructions forward or backward. If you need to preserve the order of assembly instructions, it is best to use multiple inline assembly blocks

Example of basic inline assembly
Example of basic inline assembly

Extended inline assembly

Extended inline assembly
Extended inline assembly

  • Format
    • asm keyword: indicates this is a GNU extension
    • Qualifiers (asm-qualifiers)
      • volatile: used to disable GCC optimization
      • inline: the asm assembly code will be as small as possible
      • goto: after the inline assembly ends, it jumps to a C language label

Example of extended inline assembly
Example of extended inline assembly

  • Output operands:

    Used to describe, in the instruction part,C variables that can be modifiedand constraints.

    • Each output constraint usually starts with “=”, followed by a letter that describes the operand type, and then the constraint about variable binding.
    • The output operands usually use “=” or “+” as output constraints, where “=" means the modified operand is write-only (the original value is dead before the assembly executes, and can be written to a register).”,“+" means the modified operand is readable and writable (the initial input value is preserved and used).
    • The output operands can be empty.
1
"=/+" + 约束修饰符 + 变量

Commonly used constraint modifiers include:

  • ‘r’ A register operand is allowed provided that it is in a general register.
  • Input operands:

    Used to describe, in the instruction part,**C variables that can only be read.**and constraints.

    • The parameters described in the input operands are read-only. Do not attempt to modify the contents of the input operands, because the GCC compiler assumes that the contents of the input operands are the same before and after the inline assembly.
    • In the input operands, you cannot use “=” or “+” constraints, otherwise the compiler will report an error.
    • The input operands can be empty.
  • Clobbers

    • The assembly code maymodify registers other than the output operands.
    • If the compiler is not told, it will assume that these registers remain unchanged, which may eventually lead to errors or unpredictable behavior.
    • Clobber is also amemory barriers(especially"memory"), to ensure that the compiler does not reorder or cache variables.
NameFunction
"x0","x1", …General-purpose registers are modified
"cc"Condition code registers (flags) are modified
"memory"The assembly accesses memory, ensuring the compiler flushes registers to memory and reloads them.
"redzone"Uses stack space in the x86-64 red zone.
  • "memory"Tells the GCC compiler that the inline assembly instruction changes values in memory, forcing the compiler to write all values cached in registers back to memory before executing the assembly code, and reload them after execution, in order to prevent the compiler from reordering memory accesses.
  • "cc"Indicates that the inline assembly code modifies the flag bits related to condition code/status registers.
  • Not allowed to write in the clobber list. Stack pointer register (esp/rsp)

  • Do not list output registers repeatedly.

  • The four cases can be combined; just separate them with commas.

  • Operand representation in the instruction part.
    • Operand numbering starts from 0,First list all output operands in order, then list all input operands in order.. Therefore %0 is the first output operand (or the first input operand if there are no output operands), %1 is the second, and so on.

Instruction part
Instruction part

Example from the Linux kernel
Example from the Linux kernel

Constraint modifiers for output and input operands

GCC inline operators and modifiers
GCC inline operators and modifiers

Constraint modifiers for output and input operands — general

Constraint modifiers common to output and input operands
Constraint modifiers common to output and input operands

Constraint modifiers for output and input operands — ARM64

ARM64-specific constraint modifiers for output and input operands
ARM64-specific constraint modifiers for output and input operands

Assembly symbol names instead of the % prefix

  • %[name]→ Referencing constraint variables

  • %w[name]→ Reference Low 32-bit register(such asw0, w1

  • %x[name]→ Reference Full 64-bit register(such asx0, x1

Assembly symbol names replace the % prefix
Assembly symbol names replace the % prefix

Experiment 1: Implement a simple memcpy function

Experiment 1
Experiment 1

Experiment code
Experiment code

Pitfalls and traps.

  • GDB cannot single-step into each instruction of inline assembly in source modestepiIt can single-step at the assembly level, but cannot correspond one-to-one with source lines)
  • The modifiers for the output and input parts must not be used incorrectly, otherwise the program will run incorrectly

Experiment 3: Implement the memset function using inline assembly

Experiment 3 code
Experiment 3 code

Advanced inline assembly tricks: combining with macros

  • Tip 1: Uses the C language # operator. In a parameterized macro, the ‘#’ operator, as a preprocessing operator, can convert tokens into strings.

Example from the Linux kernel
Example from the Linux kernel

123456789
#define ATOMIC_OP(op, asm_op) \static inline void atomic_##op(int i, atomic_t *v) { \    __asm__ __volatile__( \        asm_op " %1, %0" \        : "+m" (v->counter) \        : "ir" (i)); \}

You can use this macro to generate multiple atomic operation functions:

12
ATOMIC_OP(add, "addl")ATOMIC_OP(sub, "subl")

This expands to:

12345678910111213
static inline void atomic_add(int i, atomic_t *v) {    __asm__ __volatile__(        "addl %1, %0"        : "+m" (v->counter)        : "ir" (i));}static inline void atomic_sub(int i, atomic_t *v) {    __asm__ __volatile__(        "subl %1, %0"        : "+m" (v->counter)        : "ir" (i));}

Noteasm_opis a macro parameter,will be replaced with the value you provide during macro expansion, and when calling, you must pass a string literal (with double quotes), such as"addl", so that it can be directly embedded into the assembly template as an instruction string:

1
ATOMIC_OP(add, "addl")

After macro expansion, it is:

12345
__asm__ __volatile__(    "addl %1, %0"    : "+m" (v->counter)    : "ir" (i));

If you incorrectly pass in one without quotesaddl, it will be treated as an identifier rather than a string, and after expansion becomesaddl "%1, %0"causing an assembly syntax error.

##name—— Symbol concatenation (token pasting) operator

  • It directly concatenates the macro parameter and the surrounding identifiers into a new identifier (not a string).

  • Often used to generate variable names, function names, etc.

123
#define MAKE_FUNC(name) void func_##name(void) {}MAKE_FUNC(test); // Expands to: void func_test(void) {}

Experiment 4: Combining inline assembly and macros

Experiment 4
Experiment 4

Experiment 4 code
Experiment 4 code

Experiment 5: Implementing macros for reading and writing system registers

Experiment 5
Experiment 5

Experiment 5 code
Experiment 5 code

This usesGNU C statement expression Syntax:

({ ... })What is it?

  • This is a GNU extension, not standard C.

  • It allows a block of code to execute like a statement, and alsoreturn a value

  • Syntax rules:

    ({ statement1; statement2; ...; expression; })
    The last one in the code block expression(without a semicolon) is the return value.

Experiment 5: Another way to write it
Experiment 5: Another way to write it

Inline assembly: goto

The goto template of inline assembly can jump to a C language label.

goto inline assembly
goto inline assembly

  • The output section of the Goto template must be empty.
  • Add a gotolabels section that lists the C labels that are allowed as jump targets.

An example of goto inline assembly.
An example of goto inline assembly.

Experiment 6: Inline assembly with goto template.

Experiment 6
Experiment 6

Experiment 6 code.
Experiment 6 code.

%l[label]In GCC inline assembly,asm gotoa special syntax notation that indicates a jump to a label in C code.label

Detailed explanation:

  • %l[...]tells the compiler that this is alabel symbol(label), rather than an ordinary register or immediate value.
  • labelis the label name you define in C code, such as the one in your codelabel:
  • asm gotoAllows assembly code to jump directly to a label in C code via conditional jump, implementing conditional branching.
Loading comments…