[英]Mixing C and Assembly files
我想使用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!
如果要將參數傳遞給函數或返回任何需要遵守調用約定的內容。
這是一個實現“裸功能”效果的技巧示例。
#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;
}
這是我在程序集中定義函數的方法,這不需要有一個單獨的匯編程序文件,也不需要轉義每個換行符。 您只需將程序集文件的內容復制到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
我只想在上一篇文章中添加一件事。 想象一下,你想要一個接受參數的函數:(類似於
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.