1

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?

  • you can add the asm file to the command line usuall (gcc for example) and it will be dealt with properly (well mostly) and be added to the binary. Including it into C(++) then it wont/cant unless it is inline assembly. – old_timer Oct 20 '17 at 13:53
  • Different compilers differ in their support for inline assembly. As far as I know none of them use the standard C++ [`asm` keyword](http://en.cppreference.com/w/cpp/language/asm), but maybe some do. For the PC there are two main assembly language syntaxes, Intel versus AT&T, and you have to cater for that too. The best is to assemble the assembly code with an assembler, separate translation. – Cheers and hth. - Alf Oct 20 '17 at 13:54
  • 1
    Straight answer to your question would be no – Asesh Oct 20 '17 at 18:11
  • Is this a windows MSVC++ question (like Visual Studio's C++)? – Michael Petch Oct 21 '17 at 02:45
  • Including `src.c` in a C++ program will often not work either because of different sets of keywords and conflicting rules for pointer conversions. – Bo Persson Oct 21 '17 at 11:20

1 Answers1

4

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

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • I have a hunch the OP is on Windows sing MSVC – Michael Petch Oct 21 '17 at 02:44
  • @MichaelPetch: That was my guess too, but they didn't say and there is a semi-interesting answer for GNU C inline asm syntax. Does `__asm { #include "whatever" }` work at the global scope in MSVC? Or could you maybe do that inside a dummy function that you never call? – Peter Cordes Oct 21 '17 at 02:46
  • 1
    In 32-bit MSVC/C++ `__asm { }` statements (inline assembly)can't appear at global scope. In 64-bit code `__asm{}` isn't supported anymore. – Michael Petch Oct 21 '17 at 03:08