内联汇编实例

最近在跟着网上教程写内核,很累很疲惫,但也学到了许多。

且夫水之积也不厚 则其负大舟也无力

忽然想到这句话,很有道理,水平所限,好的教程是绝对写不出来的。仅以此篇作为记录之用。

代码实例

    #include "common.h"
    
    /*
    
     * %1代表输入,%0代表输出,输出要加"="号,a和dN代表寄存器约束
    
     * 行与行直接:分隔开
    
     * 最后一项代表 clobered register 即变动过的寄存器,需要GCC将其恢复原样
    
     */
    
    //端口写一个字节
    
    inline void outb(uint16_t port, uint8_t value)
    
    {
    
     asm volatile("outb %1, %0" : : "dN" (port), "a" (value));
    
    }
    
    //端口读一个字节
    
    inline uint8_t inb(uint16_t port)
    
    {
    
     uint8_t ret;
    
     asm volatile("inb %1, %0" : "=a" (ret) : "dN" (port));
    
     return ret;
    
    }
    
    //端口读入一个字
    
    inline uint16_t inw(uint16_t port)
    
    {
    
     uint16_t ret;
    
     asm volatile("inw %1, %0" : "=a" (ret) : "dN" (port));
    
     return ret;
    
    }

inline 关键字

其作用相当于宏定义,这么说不够严谨但很直观。

要比宏定义高级的多。用来修饰函数,可以在编译时直接把函数嵌入调用的主体,节省重新开栈、返回的开销。

当然你也可以通过宏定义一个函数,但是实在是想不到这样的用意在哪里,在我看来完全可以给函数起一个足够清晰的名称来省略这一步。

而 inline 所修饰的函数,调用起来和常规函数并没有什么区别,而且效率更高,因为 inline 所修饰的函数,也可以被编译器进行类型检查。

参考链接:

Linux 中 x86 的内联汇编

GCC内联汇编基础

C语言里面的内联函数(inline)与宏定义(#define)探讨