两种格式对寄存器语法的要求不同:基本格式要求寄存器前只能使用一个百分号(%),这一点和非内联汇编相同;而带有C/C++表达式格式则要求寄存器前必须使用两个百分号(%%),其原因我们会在后面讨论。
1. Output
Output用来指定当前内联汇编语句的输出。我们看一看这个例子:
__asm__("movl %%cr0, %0": "=a" (cr0));
这 个内联汇编语句的输出部分为"=r"(cr0),它是一个“操作表达式”,指定了一个输出操作。我们可以很清楚得看到这个输出操作由两部分组成:括号括住 的部分(cr0)和引号引住的部分"=a"。这两部分都是每一个输出操作必不可少的。括号括住的部分是一个C/C++表达式,用来保存内联汇编的一个输出 值,其操作就等于C/C++的相等赋值cr0 = output_value,因此,括号中的输出表达式只能是C/C++的左值表达式,也就是说它只能是一个可以合法的放在C/C++赋值操作中等号(=) 左边的表达式。那么右值output_value从何而来呢?
答案是引号中的内容,被称作“操作约束”(Operation Constraint),在这个例子中操作约束为"=a",它包含两个约束:等号(=)和字母a,其中等号(=)说明括号中左值表达式cr0是一个 Write-Only的,只能够被作为当前内联汇编的输入,而不能作为输入。而字母a是寄存器EAX / AX / AL的简写,说明cr0的值要从eax寄存器中获取,也就是说cr0 = eax,最终这一点被转化成汇编指令就是movl %eax, address_of_cr0。现在你应该清楚了吧,操作约束中会给出:到底从哪个寄存器传递值给cr0。
另外,需要特别说明的是,很多 文档都声明,所有输出操作的操作约束必须包含一个等号(=),但GCC的文档中却很清楚的声明,并非如此。因为等号(=)约束说明当前的表达式是一个 Write-Only的,但另外还有一个符号——加号(+)用来说明当前表达式是一个Read-Write的,如果一个操作约束中没有给出这两个符号中的 任何一个,则说明当前表达式是Read-Only的。因为对于输出操作来说,肯定是必须是可写的,而等号(=)和加号(+)都表示可写,只不过加号(+) 同时也表示是可读的。所以对于一个输出操作来说,其操作约束只需要有等号(=)或加号(+)中的任意一个就可以了。
二者的区别是:等号(=)表示当前操作表达式指定了一个纯粹的输出操作,而加号(+)则表示当前操作表达式不仅仅只是一个输出操作还是一个输入操作。但无论是等号(=)约束还是加号(+)约束所约束的操作表达式都只能放在Output域中,而不能被用在Input域中。
另外,有些文档声明:尽管GCC文档中提供了加号(+)约束,但在实际的编译中通不过;我不知道老版本会怎么样,我在GCC 2.96中对加号(+)约束的使用非常正常。
我们通过一个例子看一下,在一个输出操作中使用等号(=)约束和加号(+)约束的不同。










