内联汇编是指在高级语言中嵌入汇编语言片段,通常和C/C++ 语言连用。格式如下所示:
__asm__ __volatile__
(
“ 汇编语句”
…………
:输出参数列表:输入参数列表:使用的寄存器列表
);
注意:
1.使用的寄存器列表,不包含输入输出列表中的寄存器.
2.使用的寄存器应该用双%号表示。
3.每一行结束使用/n/t分隔。
4.一些常用的寄存器加载代码:a(eax),b(ebx),c(ecx),d(edx),S(esi),D(edi),m(memory),r(任意分配寄存器).
5.输出输入寄存器统一编号:%0,%1,%2……%9
__volatile__ 关键字表示防止编译器优化修改代码或者代码无返回,告知GCC ,以致产生更好的代码。一般内联汇编都会加上此关键字。
内联汇编一般用在宏定义中。
下面举个例子:
把十进制数转化成十六进制字符串。
#include <stdio.h>
#define dec2hex(dec,hex) /
({ /
__asm__ __volatile__("movl $8 , %%ecx/n/t" /
"xorl %%edi , %%edi /n/t" /
"_again:/n/t" /
"pushl %%eax/n/t" /
"andl $0x0000000f , %%eax/n/t" /
"addb $0x30 , %%al/n/t" /
"cmpb $0x3a , %%al/n/t" /
"jl output/n/t" /
"addb $7 , %%al/n/t" /
"output:/n/t" /
"movb %%al , (%%ebx,%%edi)/n/t" /
"addl $1 , %%edi/n/t" /
"popl %%eax/n/t" /
"rorl $4 , %%eax/n/t" /
"loop _again/n/t" /
"subl $4 , %%edi/n/t" /
:"=m"(hex):"b"(hex),"a"(dec):"ecx", /
"edx","edi"); /
})
int main(int argc , char ** argv)
{
char hexString[9] = {0};
int dec = atoi(argv[1]);
dec2hex(dec ,hexString);
printf("hex:%s/n" , hexString);
return 0;
}
如果采用C 语言直接编写
int main(int argc , char ** argv)
{
char hexString[9] = {0};
int dec = atoi(argv[1]);
sprintf(hexString , “%X” , dec);
printf("hex:%s/n" , hexString);
return 0;
}
编译器生成的汇编代码:
.file "test.c"
.section .rodata
.LC0:
.string "%X"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %edi
pushl %ecx
subl $48, %esp
movl 4(%ecx), %eax
addl $4, %eax
movl (%eax), %eax
movl %eax, (%esp)
call atoi
movl %eax, -12(%ebp)
leal -31(%ebp), %edi
cld
movl $19, %ecx
movl $0, %eax
rep
stosb
movl -12(%ebp), %eax
movl %eax, 8(%esp)
movl $.LC0, 4(%esp)
leal -31(%ebp), %eax
movl %eax, (%esp)
call sprintf
leal -31(%ebp), %eax
movl %eax, (%esp)
call puts
movl $0, %eax
addl $48, %esp
popl %ecx
popl %edi
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.1.2 20070502 (Red Hat 4.1.2-12)"
.section .note.GNU-stack,"",@progbits
我们可以很清楚的看到,代码调用了libc 中的用户级函数。而内联汇编直接不需要在函数调用上花销时间。并且也省去的核心态和用户态切换所花费的时间。
性能比较:
采用内联汇编执行的时间比没有采用内联汇编执行的时间少10倍。各执行1一亿次.
__asm__ __volatile__
(
“
…………
:输出参数列表:输入参数列表:使用的寄存器列表
);
注意:
1.使用的寄存器列表,不包含输入输出列表中的寄存器.
2.使用的寄存器应该用双%号表示。
3.每一行结束使用/n/t分隔。
4.一些常用的寄存器加载代码:a(eax),b(ebx),c(ecx),d(edx),S(esi),D(edi),m(memory),r(任意分配寄存器).
5.输出输入寄存器统一编号:%0,%1,%2……%9
__volatile__
内联汇编一般用在宏定义中。
下面举个例子:
把十进制数转化成十六进制字符串。
#include <stdio.h>
#define dec2hex(dec,hex) /
({ /
__asm__ __volatile__("movl $8 , %%ecx/n/t" /
"xorl %%edi , %%edi /n/t" /
"_again:/n/t" /
"pushl %%eax/n/t" /
"andl $0x0000000f , %%eax/n/t" /
"addb $0x30 , %%al/n/t" /
"cmpb $0x3a , %%al/n/t" /
"jl output/n/t" /
"addb $7 , %%al/n/t" /
"output:/n/t" /
"movb %%al , (%%ebx,%%edi)/n/t" /
"addl $1 , %%edi/n/t" /
"popl %%eax/n/t" /
"rorl $4 , %%eax/n/t" /
"loop _again/n/t" /
"subl $4 , %%edi/n/t" /
:"=m"(hex):"b"(hex),"a"(dec):"ecx", /
"edx","edi"); /
})
int main(int argc , char ** argv)
{
char hexString[9] = {0};
int dec = atoi(argv[1]);
dec2hex(dec ,hexString);
printf("hex:%s/n" , hexString);
return 0;
}
如果采用C
int main(int argc , char ** argv)
{
char hexString[9] = {0};
int dec = atoi(argv[1]);
sprintf(hexString , “%X” , dec);
printf("hex:%s/n" , hexString);
return 0;
}
编译器生成的汇编代码:
.file "test.c"
.section .rodata
.LC0:
.string "%X"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %edi
pushl %ecx
subl $48, %esp
movl 4(%ecx), %eax
addl $4, %eax
movl (%eax), %eax
movl %eax, (%esp)
call atoi
movl %eax, -12(%ebp)
leal -31(%ebp), %edi
cld
movl $19, %ecx
movl $0, %eax
rep
stosb
movl -12(%ebp), %eax
movl %eax, 8(%esp)
movl $.LC0, 4(%esp)
leal -31(%ebp), %eax
movl %eax, (%esp)
call sprintf
leal -31(%ebp), %eax
movl %eax, (%esp)
call puts
movl $0, %eax
addl $48, %esp
popl %ecx
popl %edi
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.1.2 20070502 (Red Hat 4.1.2-12)"
.section .note.GNU-stack,"",@progbits
我们可以很清楚的看到,代码调用了libc
![](https://i-blog.csdnimg.cn/blog_migrate/2f60c0bc47d4178ac5e2b807936153ff.gif)