文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>Linux 汇编代码

Linux 汇编代码

时间:2005-11-10  来源:lrh_0_2000

Linux 汇编代码 在linux内核的源代码中,以汇编语言编写的程序或程序段,有两种不同的形式。      第一种事完全的汇编代码,这样的代码采用.s作为文件的后缀。事实上,尽管是完全的汇编代码,现代的汇编工具也吸收了C语言的长处,也在汇编之前加上了一趟预处理,而预处理之前的文件则以.s为后缀。此类(.s)文件也和C程序一样,可以使用#include、#ifdef等等成分,而数据结构也一样可以在.h的文件中加以定义。   第二种是嵌在C程序中的汇编语言片断。虽然在ANSI的C语言标准中并没有关于汇编片段的规定,事实上各种实际使用的C编译中都作了这方面的扩充,而GNU的C编译gcc也在这方面作了很强的扩充。   在DOS/windows领域中,386汇编语言都采用Intel定义的语句格式。可是,在Unix领域中,采用的却是由AT&T定义的格式。   AT&T的汇编与Intel的汇编主要有以下的区别: 在Intel格式中大多使用大写字母,而在AT&T格式中都使用小写字母。 在AT&T格式中,寄存器名要加上“%”作为前缀,而在Intel格式中不带前缀。 在AT&T的386汇编语言中,指令的源操作数的顺序与在Intel的386汇编语言中正好相反。 在AT&T格式中,访问指令的操作数的宽度有操作码名称的最后一个字母(操作码的后缀决定)。用作操作码后缀的字母有b(8位)。 w(16位)和1(32位)。而在Intel格式中,则是在表示内存单元的操作数前面加上“BYTE PTR”“WORD PTR”,“DWORD PTR”来表示。 在AT$T格式中,直接操作数要加上“$”作为前缀,而在Intel格式中则不带前缀。 在AT$T格式中,绝对转移和调用指令jump/call的操作数要加上“*”作为前缀,而在intel格式则不带。 远程的转移指令和子程序调用指令的操作码名称,在AT$T格式中为“ljump”和“lcall”,而在intel格式中,则为“JMP FAR”和“CALL FAR”当转移和调用的目标为直接操作数时,两种不同的表示如下:  CALL FAR SECTION:OFFSET(Intel 格式)  JMP FAR SECTION:OFFSET(Intel 格式)  lcall $section,$offset (AT$T格式)  lcall $secton,$offset (AT$T格式). 与之相应的远程返回指令,则为:  RET FAR STACK_ADJUST (Intel 格式)  Lret $stack_adjust (AT$T 格式) 间接寻址的一般格式,两者的区别如下:  SECTION :[BASE+INDEX*SCALE+DISP](Intel 格式)  Section: disp(base,index,scale)(AT$T 格式)  当需要在C语言的程序中嵌入一段汇编语言程序时,可以使用gcc提供的“asm”语句功能。   一般而言,往C代码中插入汇编语言的代码片要比“纯粹”的汇编语言代码复杂的多,因为这里有个怎样分配使用寄存器,怎样与C代码中的变量结合的问题。为了这个目的,必须对所用的汇编语言作更多的扩充,增加对汇编工具的指导作用。其结果是其语法实际上变成了既不同于汇编语言,也不同于C语言的某种中间语言。   插入C代码的一个汇编语言代码片段可以分为四个部分,以“:”号加以分隔,其一般形式为: 指令部: 输出部:输入部:损坏部   第一部分就是汇编代码本身,其格式和在汇编语言中使用基本相同。这一部分称为“指令部”,是必须有的,而其他部分可视具体情况而省略。   当将汇编语言代码片段嵌入到C代码中时,操作数与C代码中的变量如何结合显然是个问题。Gcc采用的策略是:程序员提供具体的指令,而对寄存器的使用则一般只提供一个“样板”和一些约束条件,而把到底如何与变量结合的问题留给了gcc和gas处理。   在指令部中,数字加上前缀%,如%0、%1等等,表示需要使用的寄存器的样板操作数。可以使用的此类操作数的总数取决于具体CPU中通用寄存器的数量。这样,指令部中用到了几个不同的这种操作数,就说明有几个变量需要与寄存器结合,由gcc和gas在编译和汇编时根据后面的约束条件自行变通处理。由于这些样板操作数也使用“%”前缀,在涉及到具体的寄存器时就要在寄存器名前面加上两个“%”符,以免混淆。   紧接在指令部后面的是“输出部”,用以规定对输出变量如何结合的约束条件。每个这样的条件称为一个“约束”。必要是输出部可以有多个约束,互相以逗号分隔。每个输出约束以“=”号开始,然后是一个字母表示对操作数类型的说明,然后是关于变量结合的约束。凡是与输出部中说明的操作数相结合的寄存器或操作数本身,在执行嵌入的汇编代码后均不保留执行之前的内容,这就给gcc提供了调度这些寄存器的依据。   输出部后面是“输入部”。输入约束的格式和输出约束相似,但不带“=”号。如果一个输入约束要求使用寄存器,则在预处理时gcc会为之分配一个寄存器,并自动插入必要的指将操作数即变量的值装入该寄存器。与输入部中说明的操作数结合的寄存器或操作数本身,在执行嵌入汇编代码后也不保留执行之前的内容。   在有些操作中,除用于输入数据操作和输出数的寄存器以外,还要将若干个寄存器用于计算或操作的中间结果。这样,这些寄存器原有的内容就损坏了,所以要在损坏部队操作的副作用加以说明,让gcc采取相应的措施。   操作数的编号从输出部的第一个约束(序号为0)开始,顺序数下来,每个约束记数一次。在指令部中引用这些操作或分配用于这些操作数的寄存器时,就在序号前面加上一个“%”号。在指令部中引用一个操作数时总是把它当作一个32位的“长字”,但是对其实施的操作,则根据需要也可以是字节操作或是字操作。对操作数进行的字节操作时也允许明确指出是对哪一个字节的操作,此时在%与序号之间插入一个“b”表示最低字节,插入一个“h”表示次低字节。   表示约束调节的字母有很多: “m”“v”“o” 表示内存单元 “r” 表示任何寄存器 “q” 表示寄存器eax,ebx,ecx,edx之一 “i”和“h” 表示直接操作数 “E”和“F” 表示浮点数 “g”表示任意 “a”,“b”,“c”,“d” 分别表示寄存器eax,ebx,ecx,edx “S”和“D” 分别表示寄存器esi,edi “I” 表示常数(0至31)   此外,如果一个操作数要求使用与前某个约束中所要求的是同一个寄存器,那就把与那个约束相对应的操作数标号放在约束条件中。在损坏部常常会以 “memory”为约束条件,表示操作完成后内存中的内容已有改变,如果原来某个寄存器(也许在本次操作汇总并未使用到)的内容来自内存,则现在科能已经不一致。   还要注意,当输出部为空,即没有输出约束时,如果有输入约束存在,则必须保留分隔标记“:”号。 备注:(举例) 一 基本语法 语法上主要有以下几个不同. ★ 寄存器命名原则 AT&T: %eax Intel: eax ★源/目的操作数顺序 AT&T: movl %eax,%ebx Intel: mov ebx,eax ★常数/立即数的格式 AT&T: movl $_value,%ebx Intel: mov eax,_value 把_value的地址放入eax寄存器 AT&T: movl xd00d,%ebx Intel: mov ebx,0xd00d ★ 操作数长度标识 AT&T: movw %ax,%bx Intel: mov bx,ax ★寻址方式 AT&T: immed32(basepointer,indexpointer,indexscale) Intel: [basepointer + indexpointer*indexscale + imm32) linux工作于保护模式下,用的是32位线性地址,所以在计算地址时不用考虑segment:offset的问题.上式中的地址应为: imm32 + basepointer + indexpointer*indexscale 下面是一些例子: ★直接寻址 AT&T: _booga ; _booga是一个全局的C变量 注意加上$是表示地址引用,不加是表示值引用. 注:对于局部变量,可以通过堆栈指针引用. Intel: [_booga] ★寄存器间接寻址 AT&T: (%eax) Intel: [eax] ★变址寻址 AT&T: _variable(%eax) Intel: [eax + _variable] AT&T: _array(,%eax,4) Intel: [eax*4 + _array] AT&T: _array(%ebx,%eax,icon_cool.gif Intel: [ebx + eax*8 + _array] 二 基本的行内汇编 ·基本的行内汇编很简单,一般是按照下面的格式: asm("statements"); 例如:asm("nop"); asm("cli"); ·asm 和 __asm__是完全一样的. ·如果有多行汇编,则每一行都要加上 " " 例如: asm( "pushl %eax " "movl ,%eax " "popl %eax"); 实际上gcc在处理汇编时,是要把asm(...)的内容"打印"到汇编文件中,所以格式控制字符是必要的. 再例如: asm("movl %eax,%ebx"); asm("xorl %ebx,%edx"); asm("movl ,_booga); 在上面的例子中,由于我们在行内汇编中改变了edx和ebx的值,但是由于gcc的特殊的处理方法,即先形成汇编文件,再交给GAS去汇编,所以GAS并不知道我们已经改变了edx和ebx的值,如果程序的上下文需要edx或ebx作暂存,这样就会引起严重的后果.对于变量_booga也存在一样的问题.为了解决这个问题,就要用到扩展的行内汇编语法. 三 扩展的行内汇编 扩展的行内汇编类似于Watcom. 基本的格式是: asm ( "statements" : output_regs : input_regs : clobbered_regs); clobbered_regs指的是被改变的寄存器. 下面是一个例子(为方便起见,我使用全局变量): int count=1; int value=1; int buf[10]; void main() { asm( "cld " "rep " "stosl" : : "c" (count), "a" (value) , "D" (buf[0]) : "%ecx","%edi" ); } 得到的主要汇编代码为: movl count,%ecx movl value,%eax movl buf,%edi #APP cld rep stosl #NO_APP cld,rep,stos就不用多解释了.这几条语句的功能是向buf中写上count个value值.冒号后的语句指明输入,输出和被改变的寄存器.通过冒号以后的语句,编译器就知道你的指令需要和改变哪些寄存器,从而可以优化寄存器的分配. 其中符号"c"(count)指示要把count的值放入ecx寄存器 类似的还有: a eax b ebx c ecx d edx S esi D edi I 常数值,(0 - 31) q,r 动态分配的寄存器 g eax,ebx,ecx,edx或内存变量 A 把eax和edx合成一个64位的寄存器(use long longs) 我们也可以让gcc自己选择合适的寄存器. 如下面的例子: asm("leal (%1,%1,4),%0" : "=r" (x) : "0" (x) ); 这段代码实现5*x的快速乘法. 得到的主要汇编代码为: movl x,%eax #APP leal (%eax,%eax,4),%eax #NO_APP movl %eax,x 几点说明: 1.使用q指示编译器从eax,ebx,ecx,edx分配寄存器.使用r指示编译器从eax,ebx,ecx,edx,esi,edi分配寄存器. 2.我们不必把编译器分配的寄存器放入改变的寄存器列表,因为寄存器已经记住了它们. 3."="是标示输出寄存器,必须这样用. 4.数字%n的用法: 数字表示的寄存器是按照出现和从左到右的顺序映射到用"r"或"q"请求的寄存器.如果我们要重用"r"或"q"请求的寄存器的话,就可以使用它们. 5.如果强制使用固定的寄存器的话,如不用%1,而用ebx,则asm("leal (%%ebx,%%ebx,4),%0" : "=r" (x) : "0" (x) ); 注意要使用两个%,因为一个%的语法已经被%n用掉了. 下面可以来解释letter 4854-4855的问题: 1、变量加下划线和双下划线有什么特殊含义吗? 加下划线是指全局变量,但我的gcc中加不加都无所谓. 2、以上定义用如下调用时展开会是什么意思? #define _syscall1(type,name,type1,arg1) type name(type1 arg1) { long __res; /* __res应该是一个全局变量 */ __asm__ volatile ("int x80" /* volatile 的意思是不允许优化,使编译器严格按照你的汇编代码汇编*/ : "=a" (__res) /* 产生代码 movl %eax, __res */ : "0" (__NR_##name),"b" ((long)(arg1))); /* 如果我没记错的话,这里##指的是两次宏展开.   即用实际的系统调用名字代替"name",然后再把__NR_...展开.   接着把展开的常数放入eax,把arg1放入ebx */ if (__res >= 0) return (type) __res; errno = -__res; return -1; } by xielr(2005年10月09日,22时17分) 本文已被浏览 118 次 评论[1] | [ 收藏此页到新浪ViVi ] 网友评论 标题:Re:Linux 汇编代码 内容: 匿名网友 评论于 2005年11月10日16时39分 发表评论 标题 正文 您的姓名 您的电子邮件信箱 您的个人网页 Powered by ChinaUnix.net
相关阅读 更多 +
排行榜 更多 +
别惹神枪手安卓版

别惹神枪手安卓版

冒险解谜 下载
坦克战争世界

坦克战争世界

模拟经营 下载
丛林反击战

丛林反击战

飞行射击 下载