【版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途】
使用汇编语言笔编程最常见的方式是在高级语言(C和C++)程序内编写汇编函数,这种吧汇编语言直接写到C和C++语言程序内的技术称为内联汇编。
GNU的C编译器使用asm关键字指出使用汇编语言编写的源代码段落。asm段的基本格式如下:
asm("as code");
括号中的汇编指令必须在括号,指令超过一条的话必须使用新的行分隔汇编语言代码每一行,因为编译器逐字地取得asm段中汇编代码,并且把它们放在为程序生成的汇编代码中,有时可以使用制表符字符缩进指令以便它们和标签区别开。下面是一个简单的内联汇编的示例:
asm("movl $1, %eax\n\t movl $0,%ebx\n\tint $0x80");
该示例包括3条指令,在使用很多汇编指令时会显得有些混乱,所以一般把指令放在单独的行中。
asm("movl $1, %eax\n\t" "movl $0,%ebx\n\t" "int $0x80");
利用C全局变量可以把数据传递进和传递出内联汇编语言,注意不能使用局部变量。
#include <stdio.h> int result = 10; int main(int argc, const char *argv[]) { asm("addl $1, result\n\t" "subl $2, result\n\t"); printf("the result is %d\n", result); return 0; }
使用gcc生成汇编代码如下:
.file "inline-as.c" .globl result .data .align 4 .type result, @object .size result, 4 result: .long 10 .section .rodata .LC0: .string "the result is %d\n" .text .globl main .type main, @function main: pushl %ebp movl %esp, %ebp andl $-16, %esp subl $16, %esp #APP # 7 "inline-as.c" 1 addl $1, result subl $2, result # 0 "" 2 #NO_APP movl result, %edx movl $.LC0, %eax movl %edx, 4(%esp) movl %eax, (%esp) call printf movl $0, %eax leave ret .size main, .-main .ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-3)" .section .note.GNU-stack,"",@progbits
c文件编译执行结果为:
$ ./inline-as the result is 9 $
反编译的汇编代码中#APP和#NOAPP之间的代码为asm段指定的内联汇编代码。
ANSI C规范在使用内联汇编语句时使用关键字__asm__替换关键字asm,因为ANSI C 关键字asm用于其他用途。如下:
__asm__("addl $1, result\n\t" "subl $2, result\n\t");
基本的asm格式提供创建汇编代码的简单样式,但是有一些局限性。首先,所有输入值和输出值都必须使用C程序的全局变量,如上示例所见。其次,在内联汇编代码中不去改变任何寄存器的值。GNU编译器提供asm段的扩展格式来帮助解决这些问题。扩展格式采用新的格式,如下:
<span style="font-family:Microsoft YaHei;">asm ("as code": output location : input operands : changed registers);</span>
该格式由4个部分构成,使用冒号分隔:汇编代码、输出位置、输入操作数、改动的寄存器。在扩展asm格式中,不是所有部分必须出现。
大多数程序员把内联汇编代码定义为宏函数,定义方式和C语言类似。定义内联汇编宏函数如下:
#define CAL ({ asm("addl $1, result\n\t" "subl $2, result\n\t"); })
这里asm语句必须要在一对花括号中,以便指出语句的开头和结尾,否则编译器会生成错误信息。
如下为使用宏的一个简单示例:
#include <stdio.h> #define CAL ({ asm("addl $1, result\n\t" "subl $2, result\n\t"); }) int result = 10; int main(int argc, const char *argv[]) { CAL; printf("the result is %d\n", result); return 0; }