分类: LINUX
2009-09-21 13:21:49
转自:http://blog.163.com/beijing_light/blog/static/25915969200711210279441/ 今天看到内核的init部分,发现__asm__(......)这个宏不晓得啥意思,于是上网搜,结果就有了这篇文章。来自于sclarkca 发表于 2006-9-15 17:29:00-------------------------先拜谢了。
后例功能是将(*addr)的第nr位设为1。第一个占位符%0与C 语言变量ADDR对应,第二个占位符%1与C语言变量nr对应。因此上面的汇编语句代码与下面的伪代码等价:btsl nr, ADDR,该指令的两个操作数不能全是内存变量,因此将nr的限定字符串指定为“Ir”,将nr 与立即数或者寄存器相关联,这样两个操作数中只有ADDR为内存变量。 4、限制字符 4.1、限制字符列表 限制字符有很多种,有些是与特定体系结构相关,此处仅列出常用的限定字符和i386中可能用到的一些常用的限定符。它们的作用是指示编译器如何处理其后的C语言变量与指令操作数之间的关系。 分类 限定符 描述 通用寄存器 “a” 将输入变量放入eax 这里有一个问题:假设eax已经被使用,那怎么办? 其实很简单:因为GCC 知道eax 已经被使用,它在这段汇编代码 的起始处插入一条语句pushl %eax,将eax 内容保存到堆栈,然 后在这段代码结束处再增加一条语句popl %eax,恢复eax的内容 “b” 将输入变量放入ebx “c” 将输入变量放入ecx “d” 将输入变量放入edx “s” 将输入变量放入esi “d” 将输入变量放入edi “q” 将输入变量放入eax,ebx,ecx,edx中的一个 “r” 将输入变量放入通用寄存器,也就是eax,ebx,ecx, edx,esi,edi中的一个 “A” 把eax和edx合成一个64 位的寄存器(use long longs) 内存 “m” 内存变量 “o” 操作数为内存变量,但是其寻址方式是偏移量类型, 也即是基址寻址,或者是基址加变址寻址 “V” 操作数为内存变量,但寻址方式不是偏移量类型 “ ” 操作数为内存变量,但寻址方式为自动增量 “p” 操作数是一个合法的内存地址(指针) 寄存器或内存 “g” 将输入变量放入eax,ebx,ecx,edx中的一个 或者作为内存变量 “X” 操作数可以是任何类型 立即数 “I” 0-31之间的立即数(用于32位移位指令) “J” 0-63之间的立即数(用于64位移位指令) “N” 0-255之间的立即数(用于out指令) “i” 立即数 “n” 立即数,有些系统不支持除字以外的立即数, 这些系统应该使用“n”而不是“i” 匹配 “ 0 ”, 表示用它限制的操作数与某个指定的操作数匹配, “1” ... 也即该操作数就是指定的那个操作数,例如“0” “9” 去描述“%1”操作数,那么“%1”引用的其实就 是“%0”操作数,注意作为限定符字母的0-9 与 指令中的“%0”-“%9”的区别,前者描述操作数, 后者代表操作数。 & 该输出操作数不能使用过和输入操作数相同的寄存器 操作数类型 “=” 操作数在指令中是只写的(输出操作数) “+” 操作数在指令中是读写类型的(输入输出操作数) 浮点数 “f” 浮点寄存器 “t” 第一个浮点寄存器 “u” 第二个浮点寄存器 “G” 标准的80387浮点常数 % 该操作数可以和下一个操作数交换位置 例如addl的两个操作数可以交换顺序 (当然两个操作数都不能是立即数) # 部分注释,从该字符到其后的逗号之间所有字母被忽略 * 表示如果选用寄存器,则其后的字母被忽略 5、破坏描述部分 破坏描述符用于通知编译器我们使用了哪些寄存器或内存,由逗号格开的字符串组成,每个字符串描述一种情况,一般是寄存器名;除寄存器外还有“memory”。例如:“%eax”,“%ebx”,“memory”等。 |