Search code examples
c++assemblyinclude

Include external .asm file into C++ code


It is possible to include source code as follows:

extern "C" 
{
    #include "src.c"
}

#include "src.cpp"

Is it possible to do like this for .asm (assembly) file?


Solution

  • On thing you could do in GNU C is asm(".include \"src.s\"); at global scope to have the assembler do the including using a GAS .include assembler directive.

    This would not preprocess the asm source so you might as well just assemble it separately, and (I think) it wouldn't use the usual -I / -i include path.


    Other than that, using the C preprocessor:

    TL:DR No with most compilers, not unless you munge the asm source file into something that can go inside an asm statement at the global scope. Then sure, but why bother; building the asm separately is generally much better.


    GNU C inline-asm syntax allows you to put arbitrary assembly at the global scope to be assembled along with the compiler-generated asm. Use asm("instructions and assembler directives ..."); outside any C / C++ function.

    But to make that work when you #include a .S file (GAS syntax asm source), you'd need to get the pre-processed contents of the .S inside double quotes in the C++ source. This is not possible: C/C++, can you #include a file into a string literal?


    If you could write something like this

    int foo () { return 0; }
    
    asm ("#include \"src.S\" ");   // doesn't work
    

    in a way that would actually include the contents of src.S at that point, it would work. If you literally use this, the compiler's asm output will be:

            .file   "example.cpp"
            .text
    .Ltext0:
    #APP
            #include "src.S" 
    #NO_APP
    
    # omitted some .directives
    foo:
        xorl    %eax, %eax
        ret
    

    # is the comment character in GNU as syntax for x86, so #include "src.S" in the input to the assembler is simply treated as a comment!

    gcc foo.S runs the C pre-processor on foo.S (to produce foo.s) before feeding it to the assembler. But this doesn't happen on compiler-generated asm output; only the C/C++ source is fed through CPP before being compiled.


    You could write an asm source file that wrapped every line in double quotes, exactly like what you'd write inside the body of an asm statement.

    For example, bar.inline-asm could be

    ".p2align 4                     \n\t"
    ".globl bar                     \n\t"
    ".type  bar, @function          \n\t"
    "bar:                           \n\t"
    "     lea  (%rdi,%rsi,2), %eax  \n\t"
    "     ret                       \n\t"
    ".size   bar, .-bar             \n\t"
    

    (Note that this is GNU C Basic ASM, so we don't need to double the % characters.)

    With this src.c, we can test it:

    // extern "C"   // if this is in C++.
    int bar(int a, int b);
    
    asm(
    #include "bar.inline-asm"
    );
    
    
    int main(void) {
        return bar(2, 4);
    }
    

    I tested this, and it works:

    peter@volta:~/src/SO$ gcc -Wall -O2 include-asm.c
    peter@volta:~/src/SO$ ./a.out; echo $?
    10
    # correct result for 2 + 4*2
    
    $ disas a.out     # alias for objdump -drwC -Mintel
    
    ...
    0000000000000530 <main>:
     530:   be 04 00 00 00          mov    esi,0x4
     535:   bf 02 00 00 00          mov    edi,0x2
     53a:   e9 11 01 00 00          jmp    650 <bar>     # optimized tail-call to bar()
     53f:   90                      nop
    
    ...
    0000000000000650 <bar>:
     650:   8d 04 77                lea    eax,[rdi+rsi*2]
     653:   c3                      ret    
     654:   66 2e 0f 1f 84 00 00 00 00 00   nop    WORD PTR cs:[rax+rax*1+0x0]
     65e:   66 90                   xchg   ax,ax
    

    Obviously in this case there's zero advantage to doing this vs. simply gcc -O2 foo.c asm.S to build separate object files which are linked together at the end.

    It doesn't make name-mangling any easier, i.e. it doesn't simplify the _bar (Windows) vs. bar (Linux) situation. (See Agner Fog's calling conventions PDF, as well as his asm optimization guides if you're using x86 asm for anything.)