Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

This does not look too friendly:

__asm("command 1"
      "command 2"
      "command 3");

Do I really have to put a doublequote around every line?

Also... since multiline string literals do not work in GCC, I could not cheat with that either.

like image 724
johnny-john Avatar asked Sep 08 '10 08:09

johnny-john


People also ask

Does GCC support inline assembly?

GCC provides two forms of inline asm statements. A basic asm statement is one with no operands (see Basic Asm), while an extended asm statement (see Extended Asm) includes one or more operands.

What is __ asm __ in C?

The __asm keyword invokes the inline assembler and can appear wherever a C or C++ statement is legal. It cannot appear by itself. It must be followed by an assembly instruction, a group of instructions enclosed in braces, or, at the very least, an empty pair of braces.

Can you write assembly code in C?

We can write assembly program code inside c language program. In such case, all the assembly code must be placed inside asm{} block. Let's see a simple assembly program code to add two numbers in c program.

What is inline assembly code?

In computer programming, an inline assembler is a feature of some compilers that allows low-level code written in assembly language to be embedded within a program, among code that otherwise has been compiled from a higher-level language such as C or Ada.


2 Answers

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
);
like image 195
jyz Avatar answered Nov 02 '22 19:11

jyz


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.