Cover image for GCC Inline Assembly

GCC Inline Assembly

Words 1.4k
Views
Visitors

Timeline

Timeline

2025-09-27

init

This article introduces the basic and extended modes of GCC inline assembly, discusses in detail its core mechanisms such as syntax format, input/output constraints, clobber lists, and goto jumps, and summarizes advanced usage and common pitfalls for implementing low-level optimization operations like memcpy, memset, and system register read/write by combining C language macros and statement expressions.

Reference documents:

Inline Assembly (Inline Assembly Language) embeds assembly code in C language

Purpose:

  • Optimization: Optimize specific critical code (time-sensitive)
  • 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: usually not needed in basic inline assembly
    • inline: inline, the asm assembly code will be as small as possible
  • Assembly code block (AssemblerInstructions)

    • The GCC compiler treats inline assembly as a string

    • GCC compilation does not parse and analyze inline assembly

    • Multiple assembly instructions need to use “\n\t” for line breaks

    • GCC’s optimizer can move the position of assembly instructions. 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 code will be as small as possible
      • goto will jump to the C label after the inline assembly ends

Example of extended inline assembly
Example of extended inline assembly

  • Output section:

    Used to describe in the instruction sectionC variables that can be modifiedand constraints

    • Each output constraint usually starts with “=”, followed by a letter indicating the operand type, and then the constraint on variable binding
    • The output section usually uses “=” or “+” as output constraints, where “=" indicates that the modified operand is write-only (the original value is dead before assembly execution, and can be written to a register)”,“+" indicates that the modified operand is read-write (the initial input value will be preserved and used)
    • The output section can be empty
1
"=/+" + 约束修饰符 + 变量

Commonly used constraint modifiers include:

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

    Used to describe in the instruction sectionC variables that can only be readand constraints

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

    • The assembly code maymodify registers other than the outputs
    • If not told to the compiler, it will cause the compiler to think these registers remain unchanged, which may eventually lead to errors or unpredictable behavior.
    • Clobber is also a kind ofmemory barriers(especially"memory"), ensuring the compiler does not reorder or cache variables.
NameFunction
"x0","x1", …General-purpose registers are modified
"cc"Condition code register (flags) is modified
"memory"Assembly accesses memory, ensuring the compiler flushes registers to memory and reloads them
"redzone"Using stack space in the x86-64 redzone area
  • “memory” tells the GCC compiler that the inline assembly instruction changes values in memory, forcing the compiler to store all cached values before executing the assembly code and reload them after, with the purpose of preventing compiler reordering
  • “cc” indicates that the inline assembly code modifies the flags related to the status register
  • Not allowed to write in the clobber list Stack pointer register (esp/rsp)

  • Do not list output registers repeatedly.

  • The four possible cases can be combined, separated by commas.

  • Parameter representation in the instruction section
    • %0 corresponds to the first parameter in the output/input section, %1 represents the second parameter

Instruction section
Instruction section

Example in the Linux kernel
Example in the Linux kernel

Constraint modifiers for the output and input sections

GCC inline operators and modifiers
GCC inline operators and modifiers

Constraint modifiers for the output and input sections - General

Common constraint modifiers for the output and input sections
Common constraint modifiers for the output and input sections

Constraint modifiers for the output and input sections - ARM64

ARM64-specific constraint modifiers for the output and input sections
ARM64-specific constraint modifiers for the output and input sections

Assembly symbol name to replace the % prefix

  • %[name]→ Reference constraint variable

  • %w[name]→ Reference Lower 32-bit register(e.g.w0, w1

  • %x[name]→ Reference Complete 64-bit register(e.g.x0, x1

Assembly symbol name replacing prefix %
Assembly symbol name replacing prefix %

Experiment 1: Implementing a simple memcpy function

Experiment 1
Experiment 1

Experiment code
Experiment code

Traps and pitfalls

  • GDB cannot single-step debug inline assembly
  • Modifiers for the output and input sections cannot be used incorrectly, otherwise the program will run incorrectly

Experiment 3: Implementing the memset function using inline assembly

Experiment 3 code
Experiment 3 code

Advanced usage of inline assembly: combining with macros

  • Tip 1: Uses the ‘#’ operator in C. In macros with parameters, the ‘#’ operator acts as a preprocessor operator that can convert a token into a string

Example in the Linux kernel
Example in the Linux kernel

1
2
3
4
5
6
7
8
9
#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)); \
}


This macro can be used to generate multiple atomic operation functions:

1
2
ATOMIC_OP(add, "addl")
ATOMIC_OP(sub, "subl")

This will expand to:

1
2
3
4
5
6
7
8
9
10
11
12
13
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,which will be replaced with the value you provide during macro expansion, and a string literal (with double quotes) must be passed when calling, 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:

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

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

##name—— Token pasting operator

  • Directly concatenate the macro parameter and the surrounding identifiers to form a new identifier (not a string).

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

1
2
3
#define MAKE_FUNC(name) void func_##name(void) {}

MAKE_FUNC(test); // Expands to: void func_test(void) {}

Experiment 4: Using a combination of 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

Here we useGNU C’s statement expression Syntax:

({ ... })What is

  • 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.

Another way to write Experiment 5
Another way to write Experiment 5

Inline assembly: goto

The goto template for inline assembly, which can jump to C language label tags

goto inline assembly
goto inline assembly

  • The output section of the Goto template must be empty
  • Added a gotolabels section, which lists the C language labels that are allowed to jump to

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

Experiment 6: Inline assembly of goto template

Experiment 6
Experiment 6

Experiment 6 code
Experiment 6 code

%l[label]is in GCC inline assemblyasm gotoa special syntax, indicating a jump to a label in C codelabel

Detailed explanation:

  • %l[...]is to tell the compiler that this is alabel symbol(label), rather than a regular register or immediate value.
  • labelis the label name you defined in the C code, such as in your codelabel:
  • asm gotoallows assembly code to directly jump to a label in C code via conditional jump, implementing conditional branching.