混合C和汇编文件

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

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

在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! 

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

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

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

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

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 

这是我在程序集中定义函数的方法,这不需要有一个单独的汇编程序文件,也不需要转义每个换行符。 您只需将程序集文件的内容复制到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} )"); }; 

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

  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