一、基本内联汇编:
内联汇编代码比较容易整合到c/c++的代码中,可以做一些对于单独使用c/c++来说笨重或者不可能完成的任务。而且它还可以访问寄存器的值、访问条件码、使用一些特殊的指令和特殊的内存地址等等。
内联汇编主要用于如下场合:
1.使用汇编语言编写特定的函数;
2.编写对速度要求非常高的代码;
3.设备驱动程序中直接访问硬件;
4.编写"Naked" Call的初始化和结束代码。
C/C++与汇编可以混合使用,在内联汇编可以使用C/C++的变量和很多其它C/C++的元素。在__asm__块中可以使用以下C/C++元素:
1.符号,包括标号、变量和函数名;
2.常量,包括符号常量和枚举型(enum)成员;
3.宏定义和预处理指示符;
4.注释,包括""和"//";
5.类型名,包括所有MASM中合法的类型
6.typedef名称, 像PTR、TYPE、特定的结构成员或枚举成员这样的通用操作符。
在__asm__块中,可以使用C/C++或ASM的基数计数法(比如: 0x100和100H是相等的)。
二、gcc定义嵌入式汇编:
asm asm-qualifiers ( AssemblerTemplate:
OutputOperands[ :
InputOperands[ :
Clobbers/Modify ] ])
解析:
asm:嵌入式汇编的关键字,但为了解决在有编译选项‘-std=gnu99’的情况下 ,asm关键字会无效的问题,实际都是使用__asm__。
用来声明一个内联汇编表达式,任何一个内联汇编表达式都是以它开头的,是必不可少的。
asm-qualifiers:限定符,当是volatile(实际用__volatile__)时,表示不要对嵌入式汇编进行优化。否则当你使用了优化选项(-O)进行编译时,GCC将会根据自己的判断决定是否将这个内联汇编表达式中的指令优化掉。
如果你不想让GCC的优化影响你的内联汇编代码,你最好在前面都加上__volatile__,而不要依赖于编译器的原则,因为即使你非常了解当前编译器的优化原则,你也无法保证这种原则将来不会发生变化。而__volatile__的含义却是恒定的。
AssemblerTemplate:汇编模板,名称虽然很奇怪,但没有输入输出参数的情况下,其内容就是普通的汇编语句。
也就是"Instruction List",它是汇编指令序列。它可以是空的。
其中()里面所有的汇编语句都属于AssemblerTemplate的内容。但是,如果需要输入输出参数时,则%0表示第一个参数,%n表示第n个参数。
比如:__asm__ __volatile__(""); 或__asm__ ("");都是完全合法的内联汇编表达式,只不过这两条语句没有什么意义。
但并非所有Instruction List为空的内联汇编表达式都是没有意义的。
比如:__asm__ ("":::"memory"); 就非常有意义。
它向GCC声明:“我对内存作了改动”,GCC在编译的时候,会将此因素考虑进去。
注意的俩点:
第一就是所有寄存器都使用%%作为前缀,第二在这个部分新增了%0~%9的占位符来表示用户填充的数据。那么占位符,占的是什么位呢,谁来填充,怎么填充?%0~%9的占位符会用输出部分和输入部分指定的寄存器或变量按照出现的顺序依次填充。如果不够填充则会出现编译错误的情况。
invalid 'asm': operand number out of range
例如下面的汇编代码:
__asm__( "movl %0,%%eax \n\t" "movl %%eax,%1" :"=m" (a) :"m" (b) );
其中%0会被变量a的内存地址替换掉,%1会被变量b的内存地址替换掉。