C语言内联汇编

9 篇文章 1 订阅
4 篇文章 0 订阅

开门见山,汇编语言和C语言混合编程可分为两大类:

  1. 单独的汇编代码文件与单独的C语言分别编译成目标文件后,一起链接成可执性文件
  2. 在C语言中嵌入汇编代码,直接编译生成可执行程序

今天主要介绍第二种
内联汇编称为inline assembly, GCC支持在C代码中直接嵌入汇编代码,所以称为GCC inline assembly.
内联汇编按格式分为两大类,一类是最简单的基本内联汇编,另一类是复杂一些的扩展内联汇编.(内联汇编中所用的汇编语言是AT&T,并不是咋们熟悉的Intel语法,GCC只支持它, AT&T是汇编语言的一种语法风格,格式.在某一处理器平台上,无论汇编代码是什么语法,其编译出来的代码是一样的,所以不要误以为AT&T是一种新的机器语言.它仅仅是表达方式不同,意思是一样的)

基本内联汇编

格式: asm[volatile] ("assembly code")

  1. gcc有个优化选项 -O,可以指定优化级别.当用-O来编译时,gcc按照自己的意图优化代码,说不定就会把自己所写的代码修改了. 关键字volatile是可选项,它告诉gcc:“不要修改我的汇编代码,请原样保留”
  2. "assembly code"是咱们所写的汇编代码,他必须位于圆括号中,而且必须用双引号引起来.这是格式要求,可以为空.规则:
    (1) 指令必须用双引号引起来,无论双引号中是一条指令或多条指令
    (2) 一对引号不能跨行,如果跨行需要在结尾用反斜杠\转义
    (3) 指令之间用 ;, 换行符\n或 换行符加制表符\n\t分隔
char *str = "hello world\n";
int count = 0;
void main()
{
asm("pusha; \
    movl $4, %eax; \
    movl $1, %ebx; \
    movl str, %ecx; \
    movl $12, %edx; \
    int $0x80; \
    mov %eax, count; \
    popa \
    ");
}
扩展内联汇编

gcc本身是个C编译器, 要让其支持汇编语言,必然牵扯以下问题:

  • 在内联汇编代码插入之前的C代码,其编译后也要被分配寄存器等资源,插入的汇编代码也要使用寄存器,这是否会造成资源冲突?
  • 汇编语言如何访问C代码中的变量
    可以看到在基本内联汇编中解决这些问题的方法,是在汇编开始用pusha将所有的寄存器压栈 ,结束后出栈popa,看起来还不错,但由用户来保证数据完整性简直就是灾难,而且,运行中有大量的压栈操作,访问内存本身就比较慢,不如在编译阶段由编译器优化,直接分配给寄存器或用寄存器缓存
    最后编译器采取的做法是它提供一个模板,让用户在模板中提出要求,其余工作由它负责.
    格式asm[volatile] ("assembly code" : output : input : clobber/modify)
  1. 寄存器约束
    a : %eax, %ax, %al
    b : %ebx, %bx, %bl
    c : %ecx, %cx, %cl
    d : %edx, %dx, %dl
    S : %esi, %si
    D : %edi, %di
//  基本内联汇编
int in_a = 1, in_b = 2, out_sum;
void main()
{
asm("pusha; \
    movl in_a, %eax; \
    movl in_b, %ebx; \
    addl %ebx, %eax; \
    movl %eax, out_sum; \
    popa");
    printf("%d\n", out_sum);
}
//扩展内联汇编
void main()
{
    int in_a = 1, in_b = 2, out_sum;
    asm("addl %%ebx, %%eax" : "=a"(out_sum) : "a"(in_a), "b"(in_b));
    printf("%d\n", out_sum);
}
  1. 内存操作数约束(Memory operand constraint, m)
    当我们不想通过寄存器中转,而是直接操作内存时,可以用"m"来约束。例如:
    asm volatile ( “lock; decl %0” : “=m” (counter) : “m” (counter));
  2. 立即数约束(不太常用)
  3. 通用约束
    为方便对操作数的引用,扩展内联汇编提供了占位符,它的作用是代表约束指定的操作数(寄存器, 内存, 立即数).
    占位符分为序号占位符和名称占位符两种序号占位符是对output和input中的操作数,按照他们从左到右出现的次序从0开始编写.引用它的格式是%0~9
    asm("addl %%ebx, %%eax" : "=a"(out_sum) : "a"(in_a), "b"(in_b));
    等价于
    asm("addl %2, %1" : "=a"(out_sum) : "a"(in_a), "m"(in_b));

可以通过gcc -S -o filename.S filename.c cat filename.S来查看寄存器的使用情况,你就会明白扩展内联汇编的具体优异之处

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值