混合C和汇编文件

时间:2011-11-08 17:12:15

标签: c++ c gcc assembly x86

我想在使用g ++的C ++程序中使用naked function。不幸的是,与VC ++不同,g ++不支持裸函数,管理它的唯一方法是在单独的文件中编写自己的汇编代码并与C ++文件链接。我试图找到一些很好的x86教程来混合汇编和C / C ++文件,但找不到任何好的。

如果您了解任何问题,请告诉我。请注意,除了在C或程序集中使用它们之外,我不是要求内联汇编而是链接C和汇编文件以及在汇编中声明C的外部变量的方法,反之亦然,以及使用Makefile链接C和asm文件的方法

4 个答案:

答案 0 :(得分:17)

在C ++文件中:

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

int main() {
  foo();
}

在“裸”的asm文件中,对于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

编译,汇编和链接(用g ++而不是ld,因为用C ++这样做更容易)并运行:

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!

如果要将参数传递给函数或返回任何需要遵守调用约定的内容。

答案 1 :(得分:5)

这是一个实现“裸体功能”效果的技巧示例。

#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;
}

答案 2 :(得分:1)

我只想在上一篇文章中添加一件事。 想象一下,你想要一个接受参数的函数: (像

int add(int,int);

原型)

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

答案 3 :(得分:0)

这是我在程序集中定义函数的方法,这不需要有一个单独的汇编程序文件,也不需要转义每个换行符。您只需将程序集文件的内容复制到string-literal即可。 注意: raw multiline string literal是C ++ 11的一项功能(您还标记了C ++)。如果您想在一个.c - / .cpp文件中编译所有内容,这很有用。

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

您只能在全局范围内使用没有其他参数的基本程序集语句。 使用GCC或Clang和arm处理器时,您可以使用[[gnu::naked]] / __attribute__((naked))

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

第一种方法总是允许定义裸功能。 这也有助于制作更多可移植的代码。

    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