博客
关于我
GCC 内联汇编
阅读量:432 次
发布时间:2019-03-06

本文共 2879 字,大约阅读时间需要 9 分钟。

GNU C 内联汇编详解

内联汇编(Inline Assembly)是 GNU C 提供的一项强大特性,允许程序员在 C 代码中嵌入汇编代码。通过内联汇编,程序员可以结合 C 和汇编语言的优势,实现更高效的代码生成。然而,内联汇编的使用需要程序员对编译器的代码生成机制有深刻理解,否则可能导致代码错误或性能问题。本文将从基础到高级内容,详细介绍 GNU C 的内联汇编特性。


一、基本内联汇编

基本内联汇编是 GCC 对内联汇编的最简陋支持,主要用于理解其工作原理。基本内联汇编的语法非常简单,形式为:

asm [修饰符] ( 汇编指令 );

这里的修饰符包括 volatileinline,用于控制编译器对汇编代码的处理方式。asm 是 GNU C 提供的关键字,用于标识内联汇编块。需要注意的是,使用 asm 关键字时,若启用了 ISO C 的编译选项(如 -std=c99),则代码可能无法通过编译。因此,程序员通常使用 __asm__ 替代 asm,以确保兼容 ISO C 标准。

示例代码

__asm__ __volatile__(    "movq %rax, %rdi \n\t"      // 将 rax 寄存器的值移动到 rdi 寄存器    "movq %rbx, %rsi \n\t";     // 将 rbx 寄存器的值移动到 rsi 寄存器);

这个代码将 rax 和 rbx 寄存器的值分别移动到 rdi 和 rsi 寄存器中。编译器会直接将这些汇编指令插入到生成的机器代码中,而不会对这些代码进行优化或解析。

示例效果

编译后,反汇编结果会显示这些汇编指令被直接插入到代码中。然而,由于编译器与程序员之间缺乏信息交流,基本内联汇编的使用非常不灵活,容易导致代码错误。


二、拓展内联汇编

拓展内联汇编(Extended Inline Assembly)通过增加对编译器的信息交互,解决了基本内联汇编的局限性。程序员可以通过提供更多信息,指导编译器生成更高质量的代码。拓展内联汇编的语法结构更为复杂,形式为:

asm [修饰符] ( [汇编模板] : [输出变量] : [输入变量] : [修改的寄存器] );

核心原理

  • 信息交互:拓展内联汇编要求程序员明确指出汇编代码对输入、输出和修改寄存器的依赖关系。
  • 输出变量:程序员可以指定输出变量的分配方式,如分配到寄存器或内存。
  • 输入变量:程序员可以指定输入变量的来源,如从寄存器或内存中获取。
  • 修改列表:程序员需要告知编译器汇编代码可能修改了哪些寄存器或内存位置。
  • 示例代码

    int bittest(unsigned long long val, unsigned long long bit) {    int ret;    __asm__ __volatile__(        "movl $0, %0 \n\t"       // %0 代表 ret 寄存器        "btq %2, %1 \n\t"       // %1 代表 val 寄存器,%2 代表 bit 寄存器        "jnc %l1 \n\t"          // %l1 是 C 标签        "movl $1, %0 \n\t"       // 如果 CF 标记为 1,设置 ret 为 1        "dec %1 \n\t"            // 减少 val 的值以便返回        : "=&rm" (ret)          // ret 是输出变量,必须为左值        : "r" (val), "r" (bit)  // val 和 bit 是输入变量        : "cc", "memory", "%l1"; // 可能修改的寄存器和内存    );    return ret;}

    这个代码通过拓展内联汇编,检查 val 的特定位移位是否为 1。编译器会根据程序员提供的信息,确保 ret 变量的正确生成和返回。


    三、约束与修饰符

    1. 约束(Constraints)

    约束用于指定输入输出变量的位置和类型。常见约束包括:

    • r:通用寄存器
    • i:整型字面值
    • n:立即数
    • g:任意寄存器、内存或立即数
    • m:内存地址

    2. 修饰符(Modifiers)

    修饰符用于控制输出变量的行为,常见修饰符包括:

    • =:表示输出变量是只写的。
    • +:表示输出变量是可读写的。
    • &:表示输出变量与输入变量不重叠。
    • %:表示输出变量可以交换次序。

    示例代码

    __asm__ __volatile__(    "mov %1, %0 \n\t"       // %0 是输出变量,%1 是输入变量    : "+r" (output)         // 输出变量分配到寄存器中    : "r" (input)            // 输入变量分配到寄存器中    : "cc", "memory";        // 可能修改的寄存器和内存);

    四、输入与输出

    输入列表

    输入列表用于指定汇编代码的输入变量。语法形式为:

    [asmSymbolicName] constraint (cexpression)

    输出列表

    输出列表用于指定汇编代码的输出变量。语法形式为:

    [asmSymbolicName] constraint (cvariablename)

    五、修改列表

    修改列表用于告知编译器汇编代码可能修改了哪些寄存器或内存位置。语法形式为:

    : Clobber (cexpression)

    六、特殊寄存器与平台特性

    1. 标记寄存器

    在某些平台(如 x86),GCC 支持将标记寄存器中的标记输出到 C 变量中。标记寄存器通常用于检查条件(如除法的异常标志)。

    2. 平台特性

    • x86:支持 a(ax)、b(bx)、c(cx)、d(dx)、S(si)、D(di)等寄存器。
    • RISC-V:支持 f(浮点寄存器)、I(12 位立即数)、J(整数 0)、K(5 位无符号立即数)、A(地址寄存器)。

    七、寄存器变量

    寄存器变量是 ISO C 标准中对寄存器分配的特性扩展。程序员可以通过以下语法指定变量分配到特定寄存器中:

    register type cvariable asm ("寄存器名");

    示例代码

    register unsigned long long sum asm ("rax");  // 将 sum 分配到 rax 寄存器

    八、总结

  • 原则

    • 尽量避免使用宏和伪指令。
    • 使用 = constraint 时,不假设输入变量已被加载到寄存器中。
    • 只有在必要时才修改输入变量。
    • 尽可能提供全面信息。
    • 注意输出与输入的重叠问题,使用 & constraint 解决。
  • 注意事项

    • 小心打字错误,避免段错误。
    • 避免使用指令的操作对象类型错误。
  • 通过合理使用 GNU C 的内联汇编特性,程序员可以显著提升代码性能和可读性。

    转载地址:http://jmdyz.baihongyu.com/

    你可能感兴趣的文章
    Objective-C实现base64编码 (附完整源码)
    查看>>
    Objective-C实现base85 编码算法(附完整源码)
    查看>>
    Objective-C实现basic graphs基本图算法(附完整源码)
    查看>>
    Objective-C实现BCC校验计算(附完整源码)
    查看>>
    Objective-C实现bead sort珠排序算法(附完整源码)
    查看>>
    Objective-C实现BeadSort珠排序算法(附完整源码)
    查看>>
    Objective-C实现bellman ford贝尔曼福特算法(附完整源码)
    查看>>
    Objective-C实现bellman-ford贝尔曼-福特算法(附完整源码)
    查看>>
    Objective-C实现bellman-ford贝尔曼-福特算法(附完整源码)
    查看>>
    Objective-C实现BellmanFord贝尔曼-福特算法(附完整源码)
    查看>>
    Objective-C实现bfs 最短路径算法(附完整源码)
    查看>>
    Objective-C实现BF算法 (附完整源码)
    查看>>
    Objective-C实现Bilateral Filter双边滤波器算法(附完整源码)
    查看>>
    Objective-C实现binary exponentiation二进制幂运算算法(附完整源码)
    查看>>
    Objective-C实现binary tree mirror二叉树镜像算法(附完整源码)
    查看>>
    Objective-C实现binary tree traversal二叉树遍历算法(附完整源码)
    查看>>
    Objective-C实现binomial coefficient二项式系数算法(附完整源码)
    查看>>
    Objective-C实现bisection二分法算法(附完整源码)
    查看>>
    Objective-C实现BitMap算法(附完整源码)
    查看>>
    Objective-C实现bitonic sort双调排序算法(附完整源码)
    查看>>