汇编 | C/C++调用汇编
概述
我使用AT&T的规范,在linux上完成 C和汇编的互相调用,并使用gcc编译成可执行文件。
目标:汇编函数提供输出。类似C语言的函数
void hello_world(char* value)
{
printf(value);
}
提供给C语言调用:
int main()
{
hello_world("hello world!\n");
}
搭建AT&T的环境
- ubuntu16.04 或 ubuntu18.04- vscode- 文件后缀: .s- gcc
下载
vscode
插件GNU Assembler Language Support
C代码生成为汇编代码
提供一个hello.c
void hello_world(char* value)
{
printf(value);
}
int main()
{
hello_world("Hello World!\n");
}
为了达到使用C++调用汇编函数输出hello world!
的目的,我们需要把hello_world
函数转化为汇编语言编写,我们先将
gcc 将hello.c转化为汇编代码
$ gcc -S hello.c -o hello.s
转化之后的汇编代码:
.file "hello.c"
.text
.globl hello_world
.type hello_world, @function
hello_world:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
movl $0, %eax
call printf
nop
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size hello_world, .-hello_world
.section .rodata
.LC0:
.string "Hello World!\n"
.text
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %edi
call hello_world
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609"
.section .note.GNU-stack,"",@progbits
我们根据上面的汇编代码可以看到汇编的hello_world
汇编函数。我们可以根据自己的理解重新写一份,步骤如下:
- 在C中调用hello_world汇编函数,需要先声明:
extern hello_world(char* value);
- 编写AT&T规范的汇编代码,文件后缀是
.s
hello_world 汇编函数
hello.s
#hello.s
.globl hello_world
.type hello_world, @function
.section .text
hello_world:
pushq %rbp #压栈
movq %rsp, %rbp #把栈顶指针赋值给%rbp
subq $8, %rsp #调整栈指针,向下移动8个字节,给局部变量留出空间
movq %rdi, -8(%rbp) #把rdi的值赋值给位于rbp-8的局部变量 rdi代表第一个参数
movq -8(%rbp), %rax #把位于rbp-8的局部变量赋值给rax
#movq %rax, %rdi #rax 赋值给 rdi
movq $0, %rax #以0结尾
nop
call printf
leave
ret
- 压栈和把栈顶指针赋值给%rbp是汇编函数的常规操作,基本上每个汇编函数都需要。- 调整栈指针,给局部变量留出空间-
%rdi
代表是第一个参数- 最后字符串结尾需要加上0
-call printf
调用printf函数打印寄存器中的字符串 hello.c
extern void hello_world(char* value);
int main()
{
hello_world("Hello World!\n");
}
编译成可执行文件
$ gcc -o hello hello.c hello.s
运行
$ ./hello
Hello World!
x64
在x64汇编中调用函数时,以下寄存器用作参数。 尝试将它们提交到内存中,因为将来您会经常使用它们
第一个参数:RDI
第二个参数:RSI
第三个参数:RDX
第四个参数:RCX
第五个参数:R8
第六个参数:R9
--完--
- 原文作者: 留白
- 原文链接: https://zfunnily.github.io/2021/02/compilation/
- 更新时间:2024-04-16 01:01:05
- 本文声明:转载请标记原文作者及链接