欢迎来到冰点文库! | 帮助中心 分享价值,成长自我!
冰点文库
全部分类
  • 临时分类>
  • IT计算机>
  • 经管营销>
  • 医药卫生>
  • 自然科学>
  • 农林牧渔>
  • 人文社科>
  • 工程科技>
  • PPT模板>
  • 求职职场>
  • 解决方案>
  • 总结汇报>
  • ImageVerifierCode 换一换
    首页 冰点文库 > 资源分类 > DOCX文档下载
    分享到微信 分享到微博 分享到QQ空间

    ATT汇编与GCC内嵌汇编语法.docx

    • 资源ID:9133117       资源大小:35.33KB        全文页数:37页
    • 资源格式: DOCX        下载积分:1金币
    快捷下载 游客一键下载
    账号登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录 QQ登录
    二维码
    微信扫一扫登录
    下载资源需要1金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP,免费下载
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    ATT汇编与GCC内嵌汇编语法.docx

    1、ATT汇编与GCC内嵌汇编语法1.寄存器引用引用寄存器要在寄存器号前加百分号%,如“movl %eax, %ebx”。80386有如下寄存器:8个32-bit寄存器 %eax,%ebx,%ecx,%edx,%edi,%esi,%ebp,%esp; 8个16-bit寄存器,它们事实上是上面8个32-bit寄存器的低16位:%ax,%bx,%cx,%dx,%di,%si,%bp,%sp; 8个8-bit寄存器:%ah,%al,%bh,%bl,%ch,%cl,%dh,%dl。它们事实上是寄存器%ax,%bx,%cx,%dx的高8位和低8位; 6个段寄存器:%cs(code),%ds(data),%s

    2、s(stack), %es,%fs,%gs; 3个控制寄存器:%cr0,%cr2,%cr3; 6个debug寄存器:%db0,%db1,%db2,%db3,%db6,%db7; 2个测试寄存器:%tr6,%tr7; 8个浮点寄存器栈:%st(0),%st(1),%st(2),%st(3),%st(4),%st(5),%st(6),%st(7)。2. 操作数顺序操作数排列是从源(左)到目的(右),如“movl %eax(源), %ebx(目的)”3. 立即数使用立即数,要在数前面加符号$, 如“movl $0x04, %ebx”或者:para = 0x04movl $para, %ebx指令执行

    3、的结果是将立即数04h装入寄存器ebx。4. 符号常数符号常数直接引用如value: .long 0x12a3f2demovl value , %ebx指令执行的结果是将常数0x12a3f2de装入寄存器ebx。引用符号地址在符号前加符号$, 如“movl $value, % ebx”则是将符号value的地址装入寄存器ebx。5. 操作数的长度操作数的长度用加在指令后的符号表示b(byte, 8-bit), w(word, 16-bits), l(long, 32-bits),如“movb %al, %bl”,“movw %ax, %bx”,“movl %eax, %ebx ”。如果没有指定

    4、操作数长度的话,编译器将按照目标操作数的长度来设置。比如指令“mov %ax, %bx”,由于目标操作数bx的长度为word,那么编译器将把此指令等同于“movw %ax, %bx”。同样道理,指令“mov $4, %ebx”等同于指令“movl $4, %ebx”,“push %al”等同于“pushb %al”。对于没有指定操作数长度,但编译器又无法猜测的指令,编译器将会报错,比如指令“push $4”。6. 符号扩展和零扩展指令绝大多数面向80386的AT&T汇编指令与Intel格式的汇编指令都是相同的,符号扩展指令和零扩展指令则是仅有的不同格式指令。符号扩展指令和零扩展指令需要指定源操

    5、作数长度和目的操作数长度,即使在某些指令中这些操作数是隐含的。在AT& T语法中,符号扩展和零扩展指令的格式为,基本部分movs和movz(对应Intel语法的movsx和movzx),后面跟上源操作数长度和目的操作数长度。movsbl意味着movs (from)byte (to)long;movbw意味着movs (from)byte (to)word;movswl意味着movs (from)word (to)long。对于movz指令也一样。比如指令“movsbl %al, %edx”意味着将al寄存器的内容进行符号扩展后放置到edx寄存器中。其它的Intel格式的符号扩展指令还有:cbw

    6、 - sign-extend byte in %al to word in %ax; cwde - sign-extend word in %ax to long in %eax; cwd - sign-extend word in %ax to long in %dx:%ax; cdq - sign-extend dword in %eax to quad in %edx:%eax;对应的AT&T语法的指令为cbtw,cwtl,cwtd,cltd。7. 调用和跳转指令段内调用和跳转指令为call,ret和jmp,段间调用和跳转指令为lcall,lret和ljmp。段间调用和跳转指令的格式为“

    7、lcall/ljmp $SECTION, $OFFSET”,而段间返回指令则为“lret $STACK-ADJUST”。8. 前缀操作码前缀被用在下列的情况:字符串重复操作指令(rep,repne); 指定被操作的段(cs,ds,ss,es,fs,gs); 进行总线加锁(lock); 指定地址和操作的大小(data16,addr16);在AT&T汇编语法中,操作码前缀通常被单独放在一行,后面不跟任何操作数。例如,对于重复scas指令,其写法为:repnescas上述操作码前缀的意义和用法如下:指定被操作的段前缀为cs,ds,ss,es,fs,和gs。在AT&T语法中,只需要按照section:

    8、memory-operand的格式就指定了相应的段前缀。比如:lcall %cs:realmode_swtch 操作数地址大小前缀是“data16”和addr16,它们被用来在32-bit操作数地址代码中指定16-bit的操作数地址。 总线加锁前缀“lock”,它是为了在多处理器环境中,保证在当前指令执行期间禁止一切中断。这个前缀仅仅对ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG,DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD,XCHG指令有效,如果将Lock前缀用在其它指令之前,将会引起异常。 字符串重复操作前缀rep,r

    9、epe,repne用来让字符串操作重复“%ecx”次。9. 内存引用Intel语法的间接内存引用的格式为:section:base+index*scale+displacement而在AT&T语法中对应的形式为:section:displacement(base,index,scale)其中,base和index是任意的32-bit base和index寄存器。scale可以取值1,2,4,8。如果不指定scale值,则默认值为1。section可以指定任意的段寄存器作为段前缀,默认的段寄存器在不同的情况下不一样。如果你在指令中指定了默认的段前缀,则编译器在目标代码中不会产生此段前缀代码。下面

    10、是一些例子:-4(%ebp):base=%ebp,displacement=-4,section没有指定,由于base%ebp,所以默认的section=%ss,index,scale没有指定,则index为0。foo(,%eax,4):index=%eax,scale=4,displacement=foo。其它域没有指定。这里默认的section=%ds。foo(,1):这个表达式引用的是指针foo指向的地址所存放的值。注意这个表达式中没有base和index,并且只有一个逗号,这是一种异常语法,但却合法。%gs:foo:这个表达式引用的是放置于%gs段里变量foo的值。如果call和jum

    11、p操作在操作数前指定前缀“*”,则表示是一个绝对地址调用/跳转,也就是说jmp/call指令指定的是一个绝对地址。如果没有指定*,则操作数是一个相对地址。任何指令如果其操作数是一个内存操作,则指令必须指定它的操作尺寸(byte,word,long),也就是说必须带有指令后缀(b,w,l)。.3 GCC Inline ASMGCC 支持在C/C+代码中嵌入汇编代码,这些汇编代码被称作GCC Inline ASMGCC内联汇编。这是一个非常有用的功能,有利于我们将一些C/C+语法无法表达的指令直接潜入C/C+代码中,另外也允许我们直接写 C/C+代码中使用汇编编写简洁高效的代码。1.基本内联汇编G

    12、CC中基本的内联汇编非常易懂,我们先来看两个简单的例子:_asm_(movl %esp,%eax); / 看起来很熟悉吧!或者是_asm_(movl $1,%eax / SYS_exitxor %ebx,%ebxint $0x80);或_asm_(movl $1,%eaxrt xor %ebx,%ebxrt int $0x80 );基本内联汇编的格式是_asm_ _volatile_(Instruction List);1、_asm_asm_是GCC关键字asm的宏定义:#define _asm_ asm_asm_或asm用来声明一个内联汇编表达式,所以任何一个内联汇编表达式都是以它开头的,是

    13、必不可少的。2、Instruction ListInstruction List是汇编指令序列。它可以是空的,比如:_asm_ _volatile_(); 或_asm_ ();都是完全合法的内联汇编表达式,只不过这两条语句没有什么意义。但并非所有Instruction List为空的内联汇编表达式都是没有意义的,比如:_asm_ (:memory); 就非常有意义,它向GCC声明:“我对内存作了改动”,GCC在编译的时候,会将此因素考虑进去。我们看一看下面这个例子:$ cat example1.cint main(int _argc, char* _argv) int* _p = (int*)

    14、_argc; (*_p) = 9999; /_asm_(:memory); if(*_p) = 9999) return 5; return (*_p); 在这段代码中,那条内联汇编是被注释掉的。在这条内联汇编之前,内存指针_p所指向的内存被赋值为9999,随即在内联汇编之后,一条if语句判断_p 所指向的内存与9999是否相等。很明显,它们是相等的。GCC在优化编译的时候能够很聪明的发现这一点。我们使用下面的命令行对其进行编译:$ gcc -O -S example1.c选项-O表示优化编译,我们还可以指定优化等级,比如-O2表示优化等级为2;选项-S表示将C/C+源文件编译为汇编文件,文件

    15、名和C/C+文件一样,只不过扩展名由.c变为.s。我们来查看一下被放在example1.s中的编译结果,我们这里仅仅列出了使用gcc 2.96在redhat 7.3上编译后的相关函数部分汇编代码。为了保持清晰性,无关的其它代码未被列出。$ cat example1.smain: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax # int* _p = (int*)_argcmovl $9999, (%eax) # (*_p) = 9999 movl $5, %eax # return 5popl %ebp ret参照一下C源码和编译出的汇编代码,我们会

    16、发现汇编代码中,没有if语句相关的代码,而是在赋值语句(*_p)=9999后直接return 5;这是因为GCC认为在(*_p)被赋值之后,在if语句之前没有任何改变(*_p)内容的操作,所以那条if语句的判断条件(*_p) = 9999肯定是为true的,所以GCC就不再生成相关代码,而是直接根据为true的条件生成return 5的汇编代码(GCC使用eax作为保存返回值的寄存器)。我们现在将example1.c中内联汇编的注释去掉,重新编译,然后看一下相关的编译结果。$ gcc -O -S example1.c$ cat example1.smain: pushl %ebp movl %

    17、esp, %ebp movl 8(%ebp), %eax # int* _p = (int*)_argcmovl $9999, (%eax) # (*_p) = 9999#APP # _asm_(:memory)#NO_APPcmpl $9999, (%eax) # (*_p) = 9999 ?jne .L3 # false movl $5, %eax # true, return 5 jmp .L2 .p2align 2 .L3: movl (%eax), %eax .L2: popl %ebp ret由于内联汇编语句_asm_(:memory)向GCC声明,在此内联汇编语句出现的位置内存内

    18、容可能了改变,所以GCC在编译时就不能像刚才那样处理。这次,GCC老老实实的将if语句生成了汇编代码。可能有人会质疑:为什么要使用_asm_(:memory)向GCC声明内存发生了变化?明明“Instruction List”是空的,没有任何对内存的操作,这样做只会增加GCC生成汇编代码的数量。确实,那条内联汇编语句没有对内存作任何操作,事实上它确实什么都没有做。但影响内存内容的不仅仅是你当前正在运行的程序。比如,如果你现在正在操作的内存是一块内存映射,映射的内容是外围I/O设备寄存器。那么操作这块内存的就不仅仅是当前的程序,I/O设备也会去操作这块内存。既然两者都会去操作同一块内存,那么任何

    19、一方在任何时候都不能对这块内存的内容想当然。所以当你使用高级语言C/C+写这类程序的时候,你必须让编译器也能够明白这一点,毕竟高级语言最终要被编译为汇编代码。你可能已经注意到了,这次输出的汇编结果中,有两个符号:#APP和#NO_APP,GCC将内联汇编语句中Instruction List所列出的指令放在#APP和#NO_APP之间,由于_asm_(:memory)中“Instruction List”为空,所以#APP和#NO_APP中间也没有任何内容。但我们以后的例子会更加清楚的表现这一点。关于为什么内联汇编_asm_(:memory)是一条声明内存改变的语句,我们后面会详细讨论。刚才我

    20、们花了大量的内容来讨论Instruction List为空是的情况,但在实际的编程中,Instruction List绝大多数情况下都不是空的。它可以有1条或任意多条汇编指令。当在Instruction List中有多条指令的时候,你可以在一对引号中列出全部指令,也可以将一条或几条指令放在一对引号中,所有指令放在多对引号中。如果是前者,你可以将每一条指令放在一行,如果要将多条指令放在一行,则必须用分号(;)或换行符(n,大多数情况下n后还要跟一个t,其中n是为了换行,t是为了空出一个tab宽度的空格)将它们分开。比如:_asm_(movl %eax, %ebx sti popl %edi su

    21、bl %ecx, %ebx); _asm_(movl %eax, %ebx; sti popl %edi; subl %ecx, %ebx);_asm_(movl %eax, %ebx; stint popl %edisubl %ecx, %ebx);都是合法的写法。如果你将指令放在多对引号中,则除了最后一对引号之外,前面的所有引号里的最后一条指令之后都要有一个分号(;)或(n)或(nt)。比如:_asm_(movl %eax, %ebx stin popl %edi; subl %ecx, %ebx); _asm_(movl %eax, %ebx; stint popl %edi; subl

    22、 %ecx, %ebx);_asm_(movl %eax, %ebx; stint popl %edinsubl %ecx, %ebx);_asm_(movl %eax, %ebx; stint popl %edi; subl %ecx, %ebx);都是合法的。上述原则可以归结为:任意两个指令间要么被分号(;)分开,要么被放在两行; 放在两行的方法既可以从通过n的方法来实现,也可以真正的放在两行; 可以使用1对或多对引号,每1对引号里可以放任一多条指令,所有的指令都要被放到引号中。在基本内联汇编中,“Instruction List”的书写的格式和你直接在汇编文件中写非内联汇编没有什么不同,

    23、你可以在其中定义Label,定义对齐(.align n ),定义段(.section name )。例如:_asm_(.align 2nt movl %eax, %ebxnt test %ebx, %ecxnt jne errornt stint error: popl %edint subl %ecx, %ebx);上面例子的格式是Linux内联代码常用的格式,非常整齐。也建议大家都使用这种格式来写内联汇编代码。3、_volatile_volatile_是GCC关键字volatile的宏定义:#define _volatile_ volatile_volatile_ 或volatile是可选

    24、的,你可以用它也可以不用它。如果你用了它,则是向GCC声明“不要动我所写的Instruction List,我需要原封不动的保留每一条指令”,否则当你使用了优化选项(-O)进行编译时,GCC将会根据自己的判断决定是否将这个内联汇编表达式中的指令优化掉。那么GCC判断的原则是什么?我试验了一下,发现一条内联汇编语句如果是基本内联汇编的话(即只有“Instruction List”,没有Input/Output/Clobber的内联汇编,我们后面将会讨论这一点),无论你是否使用_volatile_来修饰, GCC 2.96在优化编译时,都会原封不动的保留内联汇编中的“Instruction Lis

    25、t”。但或许我的试验的例子并不充分,所以这一点并不能够得到保证。为了保险起见,如果你不想让GCC的优化影响你的内联汇编代码,你最好在前面都加上_volatile_,而不要依赖于编译器的原则,因为即使你非常了解当前编译器的优化原则,你也无法保证这种原则将来不会发生变化。而_volatile_的含义却是恒定的。2、带有C/C+表达式的内联汇编GCC允许你通过C/C+表达式指定内联汇编中Instrcuction List中指令的输入和输出,你甚至可以不关心到底使用哪个寄存器被使用,完全靠GCC来安排和指定。这一点可以让程序员避免去考虑有限的寄存器的使用,也可以提高目标代码的效率。我们先来看几个例子:

    26、_asm_ ( : : : memory ); / 前面提到的_asm_ (mov %eax, %ebx : =b(rv) : a(foo) : eax, ebx);_asm_ _volatile_(lidt %0: =m (idt_descr);_asm_(subl %2,%0ntsbbl %3,%1: =a (endlow), =d (endhigh): g (startlow), g (starthigh), 0 (endlow), 1 (endhigh);怎么样,有点印象了吧,是不是也有点晕?没关系,下面讨论完之后你就不会再晕了。(当然,也有可能更晕_)。讨论开始带有C/C+表达式的内

    27、联汇编格式为:_asm_volatile_(Instruction List : Output : Input : Clobber/Modify);从中我们可以看出它和基本内联汇编的不同之处在于:它多了3个部分(Input,Output,Clobber/Modify)。在括号中的4个部分通过冒号(:)分开。这4个部分都不是必须的,任何一个部分都可以为空,其规则为:如果Clobber/Modify为空,则其前面的冒号(:)必须省略。比如_asm_(mov %eax, %ebx : =b(foo) : a(inp) : )就是非法的写法;而_asm_(mov %eax, %ebx : =b(foo

    28、) : a(inp) )则是正确的。 如果Instruction List为空,则Input,Output,Clobber/Modify可以不为空,也可以为空。比如_asm_ ( : : : memory );和_asm_( : : );都是合法的写法。 如果Output,Input,Clobber/Modify都为空,Output,Input之前的冒号(:)既可以省略,也可以不省略。如果都省略,则此汇编退化为一个基本内联汇编,否则,仍然是一个带有C/C+表达式的内联汇编,此时Instruction List中的寄存器写法要遵守相关规定,比如寄存器前必须使用两个百分号(%),而不是像基本汇编格

    29、式一样在寄存器前只使用一个百分号(%)。比如 _asm_( mov %eax, %ebx : : );_asm_( mov %eax, %ebx : )和_asm_( mov %eax, %ebx )都是正确的写法,而_asm_( mov %eax, %ebx : : );_asm_( mov %eax, %ebx : )和_asm_( mov %eax, %ebx )都是错误的写法。 如果Input,Clobber/Modify为空,但Output不为空,Input前的冒号(:)既可以省略,也可以不省略。比如 _asm_( mov %eax, %ebx : =b(foo) : );_asm_( mov %eax, %ebx : =b(foo) )都是正确的。 如果后面的部分不为空,而前面的部分为空,则前面的冒号(:)都必须保留,否则无法说明不为空的部分究竟是第几部分。比如, Clobber/Modify,Output为空,而Input不为空,则Clobber/Modify前的冒号必须省略(前面的规则),而Output 前的冒号必须为保留。如果Clobber/


    注意事项

    本文(ATT汇编与GCC内嵌汇编语法.docx)为本站会员主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

    copyright@ 2008-2023 冰点文库 网站版权所有

    经营许可证编号:鄂ICP备19020893号-2


    收起
    展开