Churkin Aleksey
Churkin Aleksey

Reputation: 39

asm function with c++

I would like to add method to my class using assebler language. How can I do it? example:

main.cpp

Struct ex {
    int field1;
    asm_method(char*);
}

add.asm

asm_method: 
    //some asm code

Upvotes: 2

Views: 1887

Answers (2)

Peter Cordes
Peter Cordes

Reputation: 363980

Get asm output the compiler generates for a non-inline definition of the C++ member function, and use that as a starting point for an asm source file. This works for any ISA with any compiler that can emit valid asm (which is most of them, although apparently MSVC emits a bunch of extra junk that you have to remove.)


Example with GCC (for x86-64 GNU/Linux, but works anywhere)

Also works with clang.

e.g. g++ -O3 -fverbose-asm -masm=intel -S -o foo_func.S foo.cpp (How to remove "noise" from GCC/clang assembly output?)

That .S file is now your asm source file. Remove the compiler-generated instruction lines and insert your own.

Obviously you need to know the calling convention and other stuff like that (e.g. for x86 see https://www.agner.org/optimize/#manuals for a calling convention guide), but this will get the compiler to do the name mangling for you, for that specific target platform's ABI.

struct ex {                 // lower case struct not Struct
    int field1;
    void *asm_method(char*);   // methods need a return type
};     // struct declarations end with a ;

void *ex::asm_method(char*) {
    return this;  // easy way to find out what register `this` is passed in.
}

compiles as follows for x86-64 System V, with g++ -O3 (Godbolt with Linux gcc and Windows MSVC)

# x86-64 System V: GNU/Linux g++ -O3
# This is GAS syntax
        .intel_syntax noprefix
        .text                   # .text section is already the default at top of file

        .align 2
        .p2align 4              # aligning functions by 16 bytes is typical
        .globl  _ZN2ex10asm_methodEPc     # the symbol is global, not private to this file
        .type   _ZN2ex10asm_methodEPc, @function   # (optional) and it's a function.
_ZN2ex10asm_methodEPc:                    # a label defines the symbol
        .cfi_startproc
  ## YOUR CODE GOES HERE ##
  ## RSP-8 is aligned by 16 in x86-64 SysV and Windows ##
        mov     rax, rdi                 # copy first arg (this) to return-value register.
        ret                              # pop into program counter
        .cfi_endproc
        .size   _ZN2ex10asm_methodEPc, .-_ZN2ex10asm_methodEPc    # maybe non-optional for dynamic linking

It's probably fine to omit the .cfi stack-unwind directives from hand-written asm for leaf functions, since you're not going to be throwing C++ exceptions from hand-written asm (I hope).

Upvotes: 3

rustyx
rustyx

Reputation: 85256

This depends on your target platform and compiler/toolchain and is generally too broad a question for StackOverflow.

For example, the C++ compiler in the GCC toolchain actually generates assembly from C++, and then produces object files from that assembly. Then the linker links together multiple object files to produce an ELF module.

You can bypass the C++ compilation step for a single object file and directly write .asm files.

You can compile it the same way you compile .c: gcc myfile.S -o myfile.o.

Though you should take platform ABI into account such that you can accept function arguments and return values via the correct registers. The platform ABI also specifies the calling convention and which registers should be preserved across function calls. Finally, you need to produce correct function names according to C++ name mangling rules, or use C naming rules (which are simpler) and declare your function extern "C".

For more details see C++ to ASM linkage and for Linux ABI refer to System V ABI.

For Windows start here: calling conventions and compiling assembly in Visual Studio.

Upvotes: 3

Related Questions