C语言ASM汇编内嵌语法详解
GCC 支持在C/C代码中嵌入汇编代码这些汇编代码被称作GCC Inline ASM——GCC内联汇编。这是一个非常有用的功能有利于我们将一些C/C语法无法表达的指令直接潜入C/C代码中另外也允许我们直接写 C/C代码中使用汇编编写简洁高效的代码。1.基本内联汇编GCC中基本的内联汇编非常易懂我们先来看两个简单的例子__asm__(movl %esp,%eax); // 看起来很熟悉吧或者是12345__asm__(movl $1,%eax // SYS_exitxor %ebx,%ebxint $0x80);或12345__asm__(movl $1,%eax\r\t \xor %ebx,%ebx\r\t \int $0x80 \);基本内联汇编的格式是__asm__ __volatile__(Instruction List);1、__asm____asm__是GCC关键字asm的宏定义#define __asm__ asm__asm__或asm用来声明一个内联汇编表达式所以任何一个内联汇编表达式都是以它开头的是必不可少的。2、Instruction ListInstruction List是汇编指令序列。它可以是空的比如__asm__ __volatile__(); 或__asm__ ();都是完全合法的内联汇编表达式只不过这两条语句没有什么意义。但并非所有Instruction List为空的内联汇编表达式都是没有意义的比如__asm__ (:::memory); 就非常有意义它向GCC声明“我对内存作了改动”GCC在编译的时候会将此因素考虑进去。我们看一看下面这个例子123456789101112131415$ cat example1.cint main(int __argc, char* __argv[]){int* __p (int*)__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源文件编译为汇编文件文件名和C/C文件一样只不过扩展名由.c变为.s。我们来查看一下被放在example1.s中的编译结果我们这里仅仅列出了使用gcc 2.96在redhat 7.3上编译后的相关函数部分汇编代码。为了保持清晰性无关的其它代码未被列出。12345678910$cat example1.smain:pushl %ebpmovl %esp, %ebpmovl 8(%ebp), %eax # int* __p (int*)__argcmovl $9999, (%eax) # (*__p) 9999movl $5, %eax # return 5popl %ebpret参 照一下C源码和编译出的汇编代码我们会发现汇编代码中没有if语句相关的代码而是在赋值语句(*__p)9999后直接return 5这是因为GCC认为在(*__p)被赋值之后在if语句之前没有任何改变(*__p)内容的操作所以那条if语句的判断条件(*__p) 9999肯定是为true的所以GCC就不再生成相关代码而是直接根据为true的条件生成return 5的汇编代码GCC使用eax作为保存返回值的寄存器。我们现在将example1.c中内联汇编的注释去掉重新编译然后看一下相关的编译结果。1234567891011121314151617181920212223$ gcc -O -S example1.c$ cat example1.smain:pushl %ebpmovl %esp, %ebpmovl 8(%ebp), %eax # int* __p (int*)__argcmovl $9999, (%eax) # (*__p) 9999#APP# __asm__(:::memory)#NO_APPcmpl $9999, (%eax) # (*__p) 9999 ?jne .L3 # falsemovl $5, %eax # true, return 5jmp .L2.p2align 2.L3:movl (%eax), %eax.L2:popl %ebpret由于内联汇编语句__asm__(:::memory)向GCC声明在此内联汇编语句出现的位置内存内容可能了改变所以GCC在编译时就不能像刚才那样处理。这次GCC老老实实的将if语句生成了汇编代码。可能有人会质疑为什么要使用__asm__(:::memory)向GCC声明内存发生了变化明明“Instruction List”是空的没有任何对内存的操作这样做只会增加GCC生成汇编代码的数量。确 实那条内联汇编语句没有对内存作任何操作事实上它确实什么都没有做。但影响内存内容的不仅仅是你当前正在运行的程序。比如如果你现在正在操作的内存 是一块内存映射映射的内容是外围I/O设备寄存器。那么操作这块内存的就不仅仅是当前的程序I/O设备也会去操作这块内存。既然两者都会去操作同一块 内存那么任何一方在任何时候都不能对这块内存的内容想当然。所以当你使用高级语言C/C写这类程序的时候你必须让编译器也能够明白这一点毕竟高 级语言最终要被编译为汇编代码。你可能已经注意到了这次输出的汇编结果中有两个符号#APP和#NO_APPGCC将内联汇编语 句中Instruction List所列出的指令放在#APP和#NO_APP之间由于__asm__(:::memory)中“Instruction List”为空所以#APP和#NO_APP中间也没有任何内容。但我们以后的例子会更加清楚的表现这一点。关于为什么内联汇编__asm__(:::memory)是一条声明内存改变的语句我们后面会详细讨论。刚才我们花了大量的内容来讨论Instruction List为空是的情况但在实际的编程中Instruction List绝大多数情况下都不是空的。它可以有1条或任意多条汇编指令。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2565369.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!