原文请点击wiki中的内联汇编
有些时候我们的代码可能需要使用到硬件,比如说通过一个端口输出数据,或是从某个端口读入数据,这个时候对硬件的调用就该使用汇编语言。内联汇编(inline assembly)便是很好的选择,可以使用asm()函数插入任意的汇编代码片段到C/C++代码中。下面的汇编语言都是工作在GCC编译器,因为GCC是目前在操作系统领域中使用最为广泛的编译器。
调用asm的语法如下:
asm ( assembler template : output operands (optional) : input operands (optional) : clobbered registers list (optional) );assembler templates就是具体的汇编命令,比如movl %%eax, %%ebx,将eax寄存器的值存入ebx中。
output operands指定输出操作数,比如上面指令中的的%%eax便是输出部分,如果只使用寄存器,不需要使用C/C++变量,那么这里可以省略。
input operands指定输入操作数,也就是上边的%%eax,其它同上。
clobbered registers list修饰寄存器,指定在汇编语句中会使用到的寄存器,假如使用的这个寄存器中存了目前仍旧有用的值,那么系统就会在调用asm之前保存这个值,在调用结束后恢复值。
int a = 10, b; asm("movl %1, %%eax; movl %%eax, %0;" :"=r"(b) /*output*/ :"r"(a) /*input*/ :"%eax" /*clobbered register*/ );GCC把变量命名为%0,%1这样的格式,所以为了将变量与寄存器更好的区分,GCC便将寄存器写出%%eax这样的格式,也就是有两个%%前缀。
在上面的代码中汇编代码做的事情是:将变量%1放入eax寄存器,接着将eax中的值放到变量%0中。
按照语法中的顺序,output操作数排在input操作数之前,所以%0在这里由output operands指定,%1则由input operands指定,
上面代码中将b指定为%0,a指定为%1,所以顺利实现了b=a的赋值啦。在括号里边指明C/C++中的变量。
关于"r",指的是可以使用任意的寄存器。除此之外,"a"指EAX,”b"指EBX,”c"指ECX,"d"指EDX,“S"指ESI,“D"指EDI。比如"r"(a)便是指将a映射到任意一个寄存器中。
因为使用了eax寄存器,所以在修饰寄存器列表中对eax进行说明。
下面这段代码便是将变量EAX赋值为0:
int EAX; asm("movl $0, %0"; :"=a"(EAX) );
如果想将一个变量值传给EAX寄存器,可以按如下操作
int randomness = 4; asm("movl %0, %%eax" : :"b"(randomness) :"%eax" /*或者写成 :%%eax */ );
也可以写成
int randomness = 4; asm("movl %%ebx, %%eax" : :"b"(randomness) );
通配符wildcard限制有以下选项:
"g":
“movl $0, %0" : "=g"(x)
x可以被放到编译器想放的任意地方:一个寄存器,一个内存引用,甚至是字符常量之类的。
"r":
"movl %%es, %0" : "=r"(x)
x可以放到任意一个寄存器。
”N":
“outl %0, %1” : :"a"(0xFE), "N"(0x21)
说明“0x21"可以被用作为一个常量数值。
asm volatile("in %1, %0" : "=a"(data) : "d"(port));从port端口处读入数据放到data中
asm volatile("out %%al, %%dx" : : "a"(data), "d"(port));将数据放入到port端口处,等价于
asm volatile("out %0, %1" : : "a"(data), "d"(port));函数定义在os-lab0/include/x86/io.h
/* 读I/O端口 */ static inline uint8_t in_byte(uint16_t port) { uint8_t data; asm volatile("in %1, %0" : "=a"(data) : "d"(port)); return data; } /* 写I/O端口 */ static inline voidout_byte(uint16_t port, int8_t data) { asm volatile("out %%al, %%dx" : : "a"(data), "d"(port)); }