操作系统内核代码绝大部分使用 C 语言编写,只有一小部分使用汇编语言编写,例如与特定 体系结构 相关的代码和对性能影响很大的代码。
GCC提供了内嵌汇编的功能,可以在C代码中直接内嵌汇编语言语句,大大方便了程序设计。
代码如下:
int main() {
int b = 8;
__asm__("movl $7,%eax");
return b;
}
C 语言可以用 __asm__
来嵌套汇编指令进去。上面的代码在中间修改了 eax
寄存器的值。下面就来编译一下看看效果。
gcc -o main main.c
# 运行 gdb
gdb ./main
# 显示寄存器窗口
layout regs
如上图所示,已经把 eax
修改成 7 了,虽然最后 return b
会把 eax
设置成 8。
现在讲第二个知识点,汇编里面如何使用 C语言的变量,C语言嵌入汇编,一般都是需要操作C语言的变量的。而 C语言的变量在内存里,汇编怎么拿到这个变量的内存地址呢?代码如下:
int main() {
int num_b = 8;
__asm__("movl -4(%rbp),%eax");
return 0;
}
因为我们知道 main 函数执行其他代码之前,会弄好 rbp
寄存器,任何局部变量都会通过 rbp
压进去内存堆栈,第一个 局部变量 num_b
占4个字节。所以 rbp
移动 4字节,就能找到 num_b
的地址。
__asm__
函数通常就是把 里面的字符串,原封不动地写到 .s 汇编文件。
下面来用汇编实现一个简单的 加法 功能,代码如下:
int main() {
long num_a = 1;
long num_b = 8;
long num_rest = 0;
//利用 rcx 临时存储,保存 rcx 到堆栈,不破坏 main rcx
__asm__("mov %rcx, -32(%rbp)");
//把参数 num_a 移动到 rbx
__asm__("mov -24(%rsp),%rcx");
//把参数 num_b 加到 rbx
__asm__("add -16(%rsp),%rcx");
//把参数 rbx 的值 拷贝到 变量 num_rest 的内存地址
__asm__("mov %rcx,-8(%rsp)");
//恢复 main 的rcx
__asm__("mov -32(%rbp),%rcx");
return num_rest;
}
运行情况如下,echo $?
输出 9 ,程序正常。
上面这种写法,是比较简单的用法,gcc
其实支持 扩展的行内汇编,这个在相关阅读里面。
相关阅读:
由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 Loken1,QQ:2338195090。