Mixing C and Assembly files

后端 未结 4 948
囚心锁ツ
囚心锁ツ 2020-12-16 23:24

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

相关标签:
4条回答
  • 2020-12-17 00:02

    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;
    }
    
    0 讨论(0)
  • 2020-12-17 00:07

    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
    
    0 讨论(0)
  • 2020-12-17 00:12

    I just want to add one thing to previous post. Imagine you want a function, that accept arguments: (something like

    int add(int,int);

    prototype)

    segment .text
    global add
    
       add:
       enter 0,0
       mov eax,[ebp+8]  ; first argument
       mov ebx,[ebp+12]  ; second argument
       add eax,ebx
       leave
       ret
    
    0 讨论(0)
  • 2020-12-17 00:25

    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.

    0 讨论(0)
提交回复
热议问题