How to write multiline inline assembly code in GCC C++?

Solution 1:

I always find some examples on Internet that the guy manually insert a tab and new-line instead of \t and \n, however it doesn't work for me. Not very sure if your example even compile.. but this is how I do:

asm volatile(           // note the backslash line-continuation
   "xor %eax,%eax          \n\t\
    mov $0x7c802446, %ebx  \n\t\
    mov $1000, %ax         \n\t\
    push %eax              \n\t\
    call *%ebx             \n\t\
    add $4, %esp           \n\t\
    "
    : "=a"(retval)        // output in EAX: function return value
    :
    : "ecx", "edx", "ebx"   // tell compiler about clobbers
  // Also x87 and XMM regs should be listed.
 );

Or put double quotes around each line, instead of using \ line-continuation. C string literals separately only by whitespace (including a newline) are concatenated into one long string literal. (Which is why you need the \n inside it, so it's separate lines when it's seen by the assembler).

This is less ugly and makes it possible to put C comments on each line.

asm volatile(
    "xor %eax,%eax          \n\t"
    "mov $0x7c802446, %ebx  \n\t"
    "mov $1000, %ax         \n\t"
    "push %eax              \n\t"  // function arg
    "call *%ebx             \n\t"
    "add $4, %esp           \n\t"  // rebalance the stack: necessary for asm statements
  : "=a"(retval)
  :
  : "ecx", "edx", "ebx"    // clobbers.  Function calls themselves kill EAX,ECX,EDX
  // function calls also clobber all x87 and all XMM registers, omitted here
);

Solution 2:

C++ multiline string literals

Interesting how this question pointed me to the answer:

main.cpp

#include <cassert>
#include <cinttypes>

int main() {
    uint64_t io = 0;
    __asm__ (
        R"(
incq %0
incq %0
)"
        : "+m" (io)
        :
        :
    );
    assert(io == 2);
}

Compile and run:

g++ -o main -pedantic -std=c++11 -Wall -Wextra main.cpp
./main

See also: C++ multiline string literal

GCC also adds the same syntax as a C extension, you just have to use -std=gnu99 instead of -std=c99:

main.c

#include <assert.h>
#include <inttypes.h>

int main(void) {
    uint64_t io = 0;
    __asm__ (
        R"(
incq %0
incq %0
)"
        : "+m" (io)
        :
        :
    );
    assert(io == 2);
}

Compile and run:

gcc -o main -pedantic -std=gnu99 -Wall -Wextra main.c
./main

See also: How to split a string literal across multiple lines in C / Objective-C?

One downside of this method is that I don't see how to add C preprocessor macros in the assembly, since they are not expanded inside of strings, see also: Multi line inline assembly macro with strings

Tested on Ubuntu 16.04, GCC 6.4.0, binutils 2.26.1.

.incbin

This GNU GAS directive is another thing that should be in your radar if you are going to use large chunks of assembly: Embedding resources in executable using GCC

The assembly will be in a separate file, so it is not a direct answer, but it is still worth knowing about.