GNU C 内联汇编
GNU C 内联汇编
内核代码中有很多内联汇编,为了更好的读懂内核,上网搜罗了一些内联汇编的文章在这里,方便自己随时查阅。这篇文章比较有价值,特别是后半段引用的中国科大BBS站的一些邮件列表,“对 《gcc中的内嵌汇编语言》一文的补充说明”中的一些例子描述的很好,能够帮助更好的理解内联汇编。这里摘抄一些。
基本形式
|
|
GNU C 内联汇编以关键字__asm__
开头,表示后边部分为汇编代码; __volatile__
表示告诉编译器,不要优化后边的代码,严禁将后边的汇编语句和其他语句进行重组优化。
- 寄存器使用
%%
开头; - 立即数使用
$
开头; %0 %1 %2
用来引用输入输出部分的内容;
内联汇编一共分为四部分 : instruction
\ output operand
\ input operand
\ clobber
不同部分之间以冒号分割。
instruction
: 是汇编指令,每条指令最好以"\n\t"
结尾;output operand
: 是输出部分。 每个输出部分使用 , (逗号)分隔. “=“作为修饰符, “m"是约束符,表示存放位置, ()里面表示对应C程序变量。例如: 。input operand
: 是输入部分。 和输出部分规则一样。例如:。clobber
: 这个部分是告诉gcc在这条指令里面我们会修改什么值.
操作数限定字符
操作数限定字符串中利用规定的限定字符来描述相应的操作数,一些常用的限定字符有:(还有一些没有涉及的限定字符,参见gcc.info)
“m”:操作数是内存变量。
“o”:操作数是内存变量,但它的寻址方式必须是“偏移量”类型的, 也就是基址寻址或者基址加变址寻址。
“V”:操作数是内存变量,其寻址方式非“偏移量”类型。
" “:操作数是内存变量,其地址自动增量。
“r”:操作数是通用寄存器。
“i”:操作数是立即操作数。(其值可在汇编时确定)
“n”:操作数是立即操作数。有些系统不支持除字(双字节)以外的 立即操作数,这些操作数要用"n"而不是"i"来描述。
“g”:操作数可以是立即数,内存变量或者寄存器,只要寄存器属 于通用寄存器。
“X”:操作数允许是任何类型。
“0”,“1”,…,“9”:操作数与某个指定的操作数匹配。也就是说, 该操作数就是指定的那个操作数。例如,如果用"0"来描述”%1"操作 数,那么”%1"引用的其实就是”%0"操作数。
“p”:操作数是一个合法的内存地址(指针)。
“=":操作数在指令中是只写的(输出操作数)。
“+":操作数在指令中是读-写类型的(输入-输出操作数)。
“a”:寄存器EAX。
“b”:寄存器EBX。
“c”:寄存器ECX。
“c”:寄存器ECX。
“d”:寄存器EDX。
“q”:寄存器"a”,“b”,“c"或者"d”。-
“A”:寄存器"a"或者"d”。
“f”:浮点数寄存器。
“t”:第一个浮点数寄存器。
“u”:第二个浮点数寄存器。
“D”:寄存器di。
“S”:寄存器si。
“I”:0-31之间的立即数。(用于32位的移位指令)
“J”:0-63之间的立即数。(用于64位的移位指令)
“N”:0-255之间的立即数。(用于"out"指令)
“G”:标准的80387浮点常数。
gcc 对内嵌汇编语言的处理方式
gcc在编译内嵌汇编语言时,采取的步骤如下
- 变量输入: 根据限定符的内容将输入操作数放入合适的寄存器,如果限定符指定为立即数(“1i”)或内存变量(“m”),则该步被省略,如果限定符没有具体指定输入操作数的类型(如常用的"g”),gcc会视需要决定是否将该操作数输入到某个寄存器.这样每个占位符都与某个寄存器,内存变量,或立即数形成了一一对应的关系.这就是对第二个冒号后内容的解释.如
::"a"(foo),"i"(100),"m"(bar)
表示%0对应eax寄存器,%1对应100,%2对应内存变量bar. - 生成代码: 然后根据这种一一对应的关系(还应包括输出操作符),用这些寄存器,内存变量,或立即数来取代汇编代码中的占位符(则有点像宏操作),注意,则一步骤并不检查由这种取代操作所生成的汇编代码是否合法,例如,如果有这样一条指令
asm("movl %0,%1"::"m"(foo),"m"(bar));
如果你用gcc -c -S
选项编译该源文件,那么在生成的汇编文件中,你将会看到生成了movl foo,bar
这样一条指令,这显然是错误的.这个错误在稍后的编译检查中会被发现. - 变量输出: 按照输出限定符的指定将寄存器的内容输出到某个内存变量中,如果输出操作数的限定符指定为内存变量(“m”),则该步骤被省略.这就是对第一个冒号后内容的解释, 如
:asm("mov %0,%1":"=m"(foo),"=a"(bar):);
编译后为#APP movl foo,eax #NO_APP movl eax,bar
该语句虽然有点怪怪的,但它很好的体现了gcc的运作方式.