一:背景
早期,绝大多数的程序都是用汇编语言写的,甚至是计算机的操作系统OS/360.但是,汇编语言因其抽象程度低,无法提供类型检查。使得编写大型程序捉襟见肘。而且,汇编代码是和机器紧紧联系在一起,使得汇编语言编写的程序移植性差。
那为什么还要把汇编代码内联到c语言里呢?
二:汇编代码的优势
1.访问寄存器的值
2.访问条件码
3.使用一些特殊的指令和特殊的内存地址
……
三:怎么内联汇编
①手写汇编函数(不推荐)
新建一个.c文件里,写入函数,再通过
gcc -S 2.c
生成汇编文件,再修改汇编文件里的指令
gcc -o prog 1.c 2.s
最后链接两个文件,就ok啦。
eg:
//1.c
#include<stdio.h>
int main()
{
printf("%d\n",call());
return 0;
}
//2.c
int call()
{
return 15;
}
2.c生成的汇编代码:
.file "2.c"
.text
.globl call
.type call, @function
call:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
movl $15, %eax
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size call, .-call
.ident "GCC: (Ubuntu 6.3.0-12ubuntu2) 6.3.0 20170406"
.section .note.GNU-stack,"",@progbits
大多数都是gcc产生的伪指令.
在call函数里,函数返回15,转换成汇编即是
movl $15,%eax
现在,我们修改这条指令
movl $14,%eax
再重新编译,运行
gcc -o prog 1.c 2.s
./prog
程序就返回14,而不是15了。
②使用gcc内联汇编宏
Gcc提供了 asm帮助我们内联汇编,其语法是:(asm长得像printf函数)
asm( code-strings [ : output-list [ : input-list [ : overwrite-list ] ] ] );
现在一项一项介绍:
code-strings:这里,放你的汇编指令,用” ”括起来(就像字符串)。例如
"movq $15,%%rax" (后边解释为什么是%%rax)
如果你要内联多条汇编语句,则需要为每一条指令后添加 \n\t.保证格式。例:
"movq $15,%%rbx\n\t"
"movq %%rbx,%rax"
outputlist , inputlist , overwritelist要用:分隔
如果outputlist ,inputlist , overwritelist 有多个值,则用,分隔
output-list:类似于返回值,即你想在汇编代码里修改的值。
[name] tag (expr)
[name] 这个值在汇编代码里的名字(汇编代码用%[name]访问,所以寄存器要用2个%访问)
tag
tag | 操作权限 | 位置 |
---|---|---|
“=r” | 只写 | 寄存器 |
“+r” | 读,写 | 寄存器 |
“=m” | 只写 | 内存 |
“+m” | 读,写 | 内存 |
“=rm” | 写 | 寄存器或内存 |
“+rm” | 读,写 | 寄存器或内存 |
(expr) c语言里的左值都行
input-list 类似于参数,即你要在汇编代码里使用的值
[name] tag (expr)
[name]同上
tag
tag | 位置 |
---|---|
r | 寄存器 |
m | 内存 |
rm | 寄存器或内存 |
(expr) 同上
ovrwrite-list 这里放你要使用的寄存器 用” “括起来
这样,gcc在汇编程序时,可以把你要用的寄存器pushq保存下来
例子:
#include<stdio.h>
int call(int x,int y)
{
int sum = 0;
asm("movl %[val1],%%ebx\n\t"
"movl %[val2],%%ecx\n\t"
"addl %%ebx,%%ecx\n\t"
"movl %%ecx,%[SUM]"
:[SUM] "=r" (sum) //这个是output-list
:[val1] "r" (x),[val2] "r" (y) //这个是input-list
:"%ebx","%ecx" //这个是overwriter list
);
return sum;
}
int main()
{
int a=15;
int b=20;
printf("%d\n",call(a,b));
return 0;
}
引用
1.CS:APP3e Web Aside ASM:EASM:
Combining Assembly Code with C Programs∗
2.百度图片(侵权删)