内联汇编

嵌入式汇编基本格式:

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 表示一内存偏移地址量。到现在为止,我们应该很清楚这段程序的功能了吧!该宏函数的功能是从指定段和偏移值的内存地址处取一个字节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值