Mixing C and Assembly files

22,877

Solution 1

In C++ file:

extern "C" void foo(); // Stop name mangling games

int main() {
  foo();
}

in "naked" asm file, for x86:

# modified from http://asm.sourceforge.net/howto/hello.html

.text                   # section declaration
    .global foo

foo:

# write our string to stdout

    movl    $len,%edx   # third argument: message length
    movl    $msg,%ecx   # second argument: pointer to message to write
    movl    $1,%ebx     # first argument: file handle (stdout)
    movl    $4,%eax     # system call number (sys_write)
    int $0x80       # call kernel

# and exit

    movl    $0,%ebx     # first argument: exit code
    movl    $1,%eax     # system call number (sys_exit)
    int $0x80       # call kernel

.data                   # section declaration

msg:
    .ascii  "Hello, world!\n"   # our dear string
    len = . - msg           # length of our dear string

Compile, assemble and link (with g++ rather than ld because it's much easier to do it that way for C++) and run:

ajw@rapunzel:/tmp > g++ -Wall -Wextra test.cc -c -o test.o
ajw@rapunzel:/tmp > as -o asm.o asm.S
ajw@rapunzel:/tmp > g++ test.o asm.o
ajw@rapunzel:/tmp > ./a.out
Hello, world!

If you want to pass arguments to your function or return anything you need to respect the calling conventions.

Solution 2

Here's an example of a trick to achieve the "naked function" effect.

#include <stdio.h>

extern "C" int naked_func ();

static void
dummy ()
{
  __asm__ __volatile__
    (
     "  .global naked_func\n"
     "naked_func:\n"
     "  movq    $3141569, %rax\n"
     "  ret\n"
     );
}

int
main ()
{
  printf ("%d\n", naked_func ());
  return 0;
}

Solution 3

This is my way to define a function in assembly, this does not need to have a seperate assembler-file nor you need to escape every newline. You can just copy the contents of the assembly files into the string-literal. Note: The raw multiline string literal is a C++11 feature (you also tagged C++). This is useful, if you want to compile everything in a single .c-/.cpp-file.

extern"C" int rand_byte(void);
asm (R"(
    .globl rand_byte
rand_byte:
    call rand
    and eax, 255
    ret
)");

You can only use a basic assembly-statement without additional parameters at global scope. When using GCC or Clang and an arm processor, you are able to use [[gnu::naked]]/__attribute__((naked)).

    [[gnu::naked]]
int rand_byte(void) {
    asm volatile (R"(
        push {lr}
        bl rand
        and r0, #255
        pop {pc}
    )");
};

The first way always allows to define naked functions. This also helps to make more portable code.

    extern"C" int _cdecl rand_byte(void);
    #if defined __x86__
        // NOTE: the names are decorated with a '_' on windows 32-bit
        // You can use extern"C" int _cdecl rand_byte() asm("rand_byte");
        // to make the asm symbol name always be rand_byte, without an _
        asm volatile (R"(
            .globl _rand_byte
        _rand_byte:
            call rand
            and eax, 255
            ret
        )");
    #elif defined __x86_64__
        asm volatile (R"(
            .globl rand_byte
        rand_byte:
            call rand
            and rax, 255    # eax works here, too.  x86-32 and -64 could share the same source.
            ret
        )");
    #elif defined __arm__
        asm (R"(
            .global rand_byte
        rand_byte:
            push {lr}
            bl rand
            and r0, #255
            pop {pc}
        )");
    #else
        #error There is no code for your platform yet...
    #endif
Share:
22,877
MetallicPriest
Author by

MetallicPriest

Updated on July 14, 2022

Comments

  • MetallicPriest
    MetallicPriest almost 2 years

    I want to use a naked function in my C++ program using g++. Unfortunately g++, unlike VC++, does not support naked functions and the only way to manage this is to write your own assembly code in a separate file and link with your C++ files. I tried to find some good tutorial for x86 to mix assembly and C/C++ files but couldn't find any good one.

    Kindly let me know if you know about any. Note that I'm not asking about inline assembly but linking C and assembly files and ways to declare extern variables of C in assembly and vice versa besides using them in either C or assembly, and also ways to link the C and asm files using Makefile.