嵌入式汇编基本格式:
asm("汇编语句"
: 输出寄存器
: 输入寄存器
: 会被修改的寄存器);
输出寄存器:表示这段汇编执行完之后,哪些寄存器用于存放输出数据。
这些寄存器会分别对应一C语言表达式值或一个内存地址;
输入寄存器:表示在开始执行汇编代码时,这里指定的一些寄存器中应存放的输入值,它们也分别对应着一C变量或常数值。
会被修改的寄存器:表示你已经对其中列出的寄存器中的值进行了改动,gcc编译器不能再依赖于它原先对这些寄寄存器加载的值。如果必要的话,gcc需要重新加载这些寄存器。
——————————————————————————————————————
——————————————————————————————————————
代码实例
01 #define get_seg_byte(seg,addr) \
02 ({ \
03 register char __res; \
04 __asm__("push %%fs; \
05 mov %%ax,%%fs; \
06 movb %%fs:%2,%%al; \
07 pop %%fs" \
08 :"=a" (__res) \
09 :"" (seg),"m" (*(addr))); \
10 __res;})
这段 10 行代码定义了一个嵌入汇编语言宏函数。
通常使用汇编语句最方便的方式是把它们放在一个宏内。
用圆括号括住的组合语句(花括号中的语句)可以作为表达式使用,
其中最后的变量__res(第 10行)是该表达式的输出值。因为是宏语句,需要在一行上定义,因此这里使用反斜杠’'将这些语句连成一行。
这条宏定义将被替换到宏名称在程序中被引用的地方。
第 1 行定义了宏的名称,也即是宏函数名称 get_seg_byte(seg,addr)。
第 3 行定义了一个寄存器变量__res。第 4 行上的__asm__表示嵌入汇编语句的开始。
从第 4 行到第 7 行 的 4 条 AT&T 格式的汇编语句。
第 8 行即是输出寄存器,这句的含义是在这段代码运行结束后将 eax 所代表的寄存器的值放入__res变量中,作为本函数的输出值,"=a"中的"a"称为加载代码,"="表示这是输出寄存器。
第 9 行表示在这段代码开始运行时将 seg 放到 eax 寄存器中,"“表示使用与上面同个位置的输出相同的寄存器。而(* (addr))表示一个内存偏移地址值。为了在上面汇编语句中使用该地址值,嵌入汇编程序规定把输出和输入寄存器统一按顺序编号,顺序是从输出寄存器序列从左到右从上到下以”%0"开始,分别记为%%1、…%9。
因此,输出寄存器的编号是%0(这里只有一个输出寄存器),输入寄存器前一部分("" (seg))的编号是%1,而后部分的编号是%2。
上面第 6 行上的%2 即代表(* (addr))这个内存偏移量。
现在我们来研究 4—7 行上的代码的作用。
第一句将 fs 段寄存器的内容入栈;
第二句将 eax 中的段值赋给 fs 段寄存器;
第三句是把 fs:(*(addr))所指定的字节放入 al 寄存器中。当执行完汇编语句后,输出寄存器 eax 的值将被放入__res,作为该宏函数(块结构表达式)的返回值。
通过上面分析,我们知道,宏名称中的 seg 代表一指定的内存段值,而 addr 表示一内存偏移地址量。到现在为止,我们应该很清楚这段程序的功能了吧!该宏函数的功能是从指定段和偏移值的内存地址处取一个字节。