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
    评论
CLion 是 JetBrains 公司开发的一款集成开发环境 (IDE),主要用于 C 和 C++ 编程。在 CLion 中,内联汇编(Inline Assembler)允许开发者在编写 C 或 C++ 代码时直接嵌入汇编指令,以利用硬件级别的性能优化或者处理特定平台特有的低级操作。 以下是使用 CLion 进行内联汇编的一些关键步骤和注意事项: 1. **启用内联汇编支持**:确保你的 CLion 配置支持内联汇编。在“Build, Execution, Deployment”(构建、执行和部署)菜单中,选择“CMake”,然后在生成器的配置中启用对 inline assembly 的支持。 2. **插入汇编代码**:在需要使用内联汇编的地方,通常使用 `asm` 关键字,后跟括号括起的汇编指令。例如: ```cpp int x = 0; asm volatile ("movl %1, %0" : "=r"(x) : "r"(42)); ``` 3. **声明和管理内存**:内联汇编需要手动管理内存,使用 `%` 符号指定寄存器或内存地址。例如,`%eax` 表示 EAX 寄存器,`%edi` 表示 EDI 寄存器,`%esp` 则是栈指针。 4. **调试和检查**:由于内联汇编不被编译器完全理解和跟踪,可能需要使用汇编查看器或者断点来检查执行过程。CLion 提供了一些辅助工具,如 Disassembly view(反汇编视图)。 5. **注意兼容性和限制**:不是所有处理器架构都支持内联汇编,且不同编译器对它的处理方式可能不同。务必确保你的目标平台支持,并在编译时正确设置目标架构。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值