Skip to content
Search

Inline assembler

lastmod 2018-08-17created 2015-04-0412 edits

Intro

In inline assembly, you need to specify the following.

  • assembly code
  • output variables
  • input variables
  • registers whose values change besides the output
__asm__ __volatile__ (asms : output : input : clobber);
__asm__
Inline assembly keyword.
This keyword can also be written as asm, but asm is not defined when compiling with the ansi option, so it is better to write __asm__.
__volatile__
This keyword pins the inline assembly so that optimization does not remove or change it.
According to the GCC manual, if the assembly is considered to have no side effects, an optimization may remove it or move it out of a loop.
For example, if there is an output but the variable used as the output is never used afterward, the compiler assumes the inline assembly has no effect on program execution and removes it. Of course, if you specify the conditions precisely it will work correctly even without adding __volaitile__, but it sometimes goes wrong in unexpected ways, so it is better to think carefully when writing inline assembly and add __volatile__.
asms
Assembly string enclosed in double quotes. Inside the string, input and output arguments can be used in the form %n, and after the arguments are substituted they appear as-is in the compiled assembly.
output
A comma-separated list of "constraint"(variable) entries, each representing an output argument used in the inline assembly.
input
Same form as output, and represents the input arguments.
clobber
A comma-separated list of register names enclosed in double quotes, representing registers that do not appear in input or output but whose values change as a result of running the assembly.

Note that ouput, input, and clobber can be omitted from the end if they are empty. However, when a preceding parameter is empty, it must be marked with :.

Example

An example that actually uses input and output is shown below.

int test_and_set_bit(int nr, volatile unsigned * addr)
{
    int oldbit;

    __asm__ __volatile__(
        "lock; btsl %2,%1\n\tsbbl %0,%0"
        :"=r" (oldbit),"=m" (*addr)
        :"r" (nr));
        return oldbit;
}

Simple example

Suppose we have the following code with all unnecessary code removed.

int main()
{
    int a = 11;
    return 0;
}

You can inspect the asm code with objdump1 as shown below.

_main:
       0:   55  pushq   %rbp
       1:   48 89 e5    movq    %rsp, %rbp
       4:   31 c0   xorl    %eax, %eax
       6:   c7 45 fc 00 00 00 00    movl    $0, -4(%rbp)
       d:   c7 45 f8 0b 00 00 00    movl    $11, -8(%rbp)
      14:   5d  popq    %rbp
      15:   c3  retq

On line d, you can see the code that inserts 11 into rbp.

Inline asm code that changes the value of a to 20 can be applied as follows.

#include <stdio.h>
int main()
{
    int a = 11;
    __asm__ __volatile__ ("movl $20, -8(%rbp)");
    printf("%d", a);
    return 0;
}

When you run it, you can see that 20 is printed.

See also

Favorite site

References


  1. objdump -d main.o ↩

  2. KLDPWiki-Docbook_Sgml_GCC_Inline_Assembly-KLDP.pdf ↩

  3. Introduction_to_x64_Assembly_-_kor.pdf ↩