X86汇编入门-如何在C语言中使用汇编 - 弦外之音

/ 0评 / 0

操作系统内核代码绝大部分使用 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 其实支持 扩展的行内汇编,这个在相关阅读里面。

相关阅读:

  1. https://bbs.pku.edu.cn/attach/ca/dd/cadde373e533b3ea/chapter2.pdf

由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 Loken1,QQ:2338195090。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注