`
Poechant
  • 浏览: 227447 次
博客专栏
Bebe66e7-3a30-3fc9-aeea-cfa3b474b591
Nginx高性能Web服务...
浏览量:24243
5738817b-23a1-3a32-86de-632d7da73b1e
Cumulus实时媒体服务...
浏览量:22047
社区版块
存档分类
最新评论

GCC内联汇编(2)GCC生成汇编代码简单实例

 
阅读更多

GCC内联汇编(2)GCC生成汇编代码简单实例

  • 作者:柳大·Poechant(钟超)
  • 邮箱:zhongchao.ustc#gmail.com(# -> @)
  • 博客:Blog.CSDN.net/Poechant
  • 日期:July 8th, 2012

1 准备示例

先看一个空的 main 函数会生成怎样的汇编代码。要注意的是我这里是在 Mac OS X 上进行的测试,编译器是 Apple’s version of GCC,实际上用的是 llvm-gcc。

[代码段-1]


int main() {
    return 0;
}

[命令行-1]


gcc -S main.c

生成的汇编如下(这里只截取主要部分,下同):

[代码段-2]


Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    movl    $0, -8(%rbp)
    movl    -8(%rbp), %eax
    movl    %eax, -4(%rbp)
    movl    -4(%rbp), %eax
    pop     %rbp
    ret
Leh_func_end1:

如果开启优化编译选项呢?一定会有一些变化吧。

[命令行-2]


gcc -S main.c -O3

[代码段-3]


Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    xorl    %eax, %eax
    popq    %rbp
    pop     %rbp
    ret
Leh_func_end1:

是的,一些“废话”被优化掉了。

[代码段-4]


int main() {
    int a = 19, b = 100;
    return 0;
}

看下面的简单实例,声明两个整形变量,并赋以初值。

[命令行-3]


gcc -S main.c

生成的汇编代码如下。可以看到 a 代表的局部变量值 19 被压入栈中,位置是栈基址减去 12,b 代表的局部变量压入栈中,位置是栈基址减去 16,而返回值所使用的立即数 0 被放入栈基址减去 8。

[代码段-5]


Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    movl    $19, -12(%rbp)
    movl    $100, -16(%rbp)
    movl    $0, -8(%rbp)
    movl    -8(%rbp), %eax
    movl    %eax, -4(%rbp)
    movl    -4(%rbp), %eax
    pop     %rbp
    ret
Leh_func_end1:

如果打开优化编译选项编译,则会把int a = 19, b = 100这句优化掉,从而与[代码段-3]一样。

2 内联汇编实例


int main(){
    int a = 19, b = 100;
    __asm__ (
        "addl %2, %1";
        : "=a"(a)
        : "a"(a), "b"(b)
        : "%eax", "%ebx"
    )
    return 0;
}

生成的汇编如下:


_main:
Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    pushq   %rbx
    subq    $24, %rsp
Ltmp2:
    movl    $19, -20(%rbp) # 局部变量 a 的位置是栈基址减去 20
    movl    $100, -24(%rbp) # 局部变量 b 的位置是栈基址减去 24
    
    # 处理内敛汇编的入口
    movl    -20(%rbp), %eax
    movl    -24(%rbp), %ecx
    movl    %ecx, %ebx
    
    ## InlineAsm Start
    addl    %ebx, %eax;
    ## InlineAsm End
    movl    %eax, -20(%rbp) # 返回值放在指定的局部变量 a 中
    
    # 剩下的部分与前面的简单实例一样,就是处理返回值
    movl    $0, -16(%rbp)
    movl    -16(%rbp), %eax
    movl    %eax, -12(%rbp)
    movl    -12(%rbp), %eax
    popq    %rbx
    popq    %rbp
    ret 
Leh_func_end1:

#include <stdio h=""></stdio><stdio h=""><span class="keyword" style="font-weight: bold; ">int</span> main() {
    <span class="keyword" style="font-weight: bold; ">int</span> a = <span class="number" style="color: rgb(0, 136, 0); ">19</span>, b = <span class="number" style="color: rgb(0, 136, 0); ">100</span>;
    __asm__ (
        <span class="string" style="color: rgb(136, 0, 0); ">"addl %1, %0;"</span>
        : <span class="comment" style="color: rgb(136, 136, 136); ">//no output</span>
        : <span class="string" style="color: rgb(136, 0, 0); ">"a"</span>(a), <span class="string" style="color: rgb(136, 0, 0); ">"b"</span>(b)
        : <span class="string" style="color: rgb(136, 0, 0); ">"%eax"</span>, <span class="string" style="color: rgb(136, 0, 0); ">"%ebx"</span>
    );  
    <span class="keyword" style="font-weight: bold; ">return</span> <span class="number" style="color: rgb(0, 136, 0); ">0</span>;
}
</stdio>

_main:
Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    pushq   %rbx
Ltmp2:
    # Immediate numbers
    movl    $19, -20(%rbp)
    movl    $100, -24(%rbp)
    
    # Input
    movl    -20(%rbp), %eax
    movl    -24(%rbp), %ecx
    movl    %ecx, %ebx
    
    ## InlineAsm Start
    addl %ebx, %eax;
    ## InlineAsm End
    
    # Note: no output
    
    # Similar to above examples
    movl    $0, -16(%rbp)
    movl    -16(%rbp), %eax
    movl    %eax, -12(%rbp)
    movl    -12(%rbp), %eax
    popq    %rbx
    popq    %rbp
    ret 
Leh_func_end1:

也间接证实了%0,%1,%2⋯⋯ 是从输出开始排序的,如果没有输出,就从输入开始排序。

另外使用m则可以表示memory,即变量是在内存中,而非寄存器中。如下示例:


#include <stdio h=""></stdio><stdio h=""><span class="keyword" style="font-weight: bold; ">int</span> main() {
    <span class="keyword" style="font-weight: bold; ">int</span> a = <span class="number" style="color: rgb(0, 136, 0); ">17</span>, b = <span class="number" style="color: rgb(0, 136, 0); ">100</span>;
    __asm__ (
        <span class="string" style="color: rgb(136, 0, 0); ">"addl %2, %1;"</span>
        : <span class="string" style="color: rgb(136, 0, 0); ">"=m"</span>(a)
        : <span class="string" style="color: rgb(136, 0, 0); ">"m"</span>(a), <span class="string" style="color: rgb(136, 0, 0); ">"b"</span>(b)
        : <span class="string" style="color: rgb(136, 0, 0); ">"memory"</span>, <span class="string" style="color: rgb(136, 0, 0); ">"%ebx"</span>
    );  
    printf(<span class="string" style="color: rgb(136, 0, 0); ">"%d\n"</span>, a); 
    <span class="keyword" style="font-weight: bold; ">return</span> <span class="number" style="color: rgb(0, 136, 0); ">0</span>;
}
</stdio>

生成的汇编代码的主要部分如下:


movl    $17, -20(%rbp)
movl    $100, -24(%rbp)
movl    -24(%rbp), %eax
movl    %eax, %ebx

## InlineAsm Start
addl    %ebx, -20(%rbp)
## InlineAsm End

## 下面的部分同此前的所有代码段,略去

可以看到是直接加到操作上的,而非寄存器。

-

转载请注明来自柳大的CSDN博客:Blog.CSDN.net/Poechant

-

分享到:
评论

相关推荐

    内联汇编2.rar

    标题"内联汇编2.rar"暗示了这是一个关于内联汇编的进阶主题,可能包含了更复杂的用法和实例。这个压缩包可能包含了教程、代码示例以及与内联汇编相关的资源。 描述虽然简单,但可以推断出这个压缩包的内容是专注于...

    AVR-GCC如何调用存储于Flash中的指向函数的指针

    开发者在编写类似代码时,应该熟悉AVR-GCC编译器的特性和AVR微控制器的硬件特性,以确保程序的正确性和效率。同时,为了确保代码的安全性和稳定性,应当尽量避免在Flash中存储大量数据,以及在运行时频繁地读取Flash...

    gcc-inline-assembly

    GCC内联汇编的语法通常包含以下几个部分: - `asm` 关键字:标志着内联汇编的开始。 - 汇编指令:具体的汇编代码,根据目标处理器架构(如x86、ARM等)编写。 - 输入输出约束:定义汇编指令如何与C/C++变量交互,...

    ASm_Gcc.rar_内嵌汇编

    AT&T汇编语言是一种常用的x86汇编语法,它在GCC(GNU Compiler Collection)中被广泛支持,用于编写内联汇编代码。本资料集合将深入探讨AT&T汇编语言和GCC内嵌汇编的使用,为学习汇编语言的开发者提供宝贵的资源。 ...

    单片机C语言和汇编语言混合编程实例详解

    例如,使用GCC编译器,你可以使用`__asm__`关键字来定义内联汇编。这种方式更加灵活,因为汇编代码可以接受和返回C语言的变量,并且可以有条件地执行。 混合编程实例通常涉及以下几个方面: 1. **中断服务程序**:...

    gcc manual gcc手册

    3. **预处理、编译、汇编和链接**:GCC将源代码分别通过预处理器、编译器、汇编器和链接器四个步骤转化为可执行文件。手册会深入解析每个步骤的功能和相关参数。 4. **调试与优化**:GCC支持生成调试信息(如-G选项...

    C++程序同汇编程序混合调用的源代码

    3. **C++编译器支持**:不是所有的C++编译器都支持内联汇编,例如GCC和Clang支持,但Visual C++可能需要特殊处理。 4. **类型转换**:C++中的数据类型需要与汇编中的数据类型匹配。例如,C++中的整型可能需要在汇编...

    c_0.rar_in

    在大多数情况下,现代编译器已经能够生成高效的机器码,因此在考虑使用内联汇编之前,应先尝试优化C代码。 4. **副作用和约束**:内联汇编中的输入和输出操作数需要明确指定,以便编译器知道哪些变量和寄存器会被...

    att汇编实例 linux

    根据提供的信息,我们可以总结出以下关于“att汇编实例 Linux”的相关知识点: ### 1. AT&T 汇编语法简介 AT&T汇编语法是GNU汇编器(GNU Assembler,简称`gas`)使用的一种汇编语言语法风格,与Intel语法不同,...

    linux编译器GCC编译手册

    ### Linux GCC编译器内联汇编使用指南 #### 概述 GCC(GNU Compiler Collection)作为GNU项目的一部分,是一款广泛应用于Linux环境下的开源编译器。它支持多种编程语言,如C、C++等,并提供了强大的功能集,包括...

    gcc编译器用户手册

    12. **代码生成选项(CODEGENERATIONOPTION)**: - `-mfpmath`:指定浮点运算方式。 GCC的选项众多,合理利用这些选项,可以显著提升编译质量和性能。开发者应当根据具体项目的需求,灵活配置编译选项,以达到...

    GCC 4.9用户手册

    - **内联汇编支持**:允许在 C/C++ 代码中嵌入汇编指令。 - **属性系统**:用于向编译器传递额外信息,以辅助优化或错误检查。 - **多线程支持**:GCC 4.9 支持使用 OpenMP 来编写并行代码。 - **链接时间优化**:...

    avr的gcc编程(初学者必看)

    - **C代码中内联汇编程序**: - **内联汇编**: 在C代码中插入汇编指令,实现对底层硬件的精确控制。 - **应用场景**: 高性能计算、中断处理等。 - **独立的汇编语言支持**: - **纯汇编程序**: 编写完全由汇编语言...

    GNU_GCC.rar_GNU_gnu gcc

    5. **汇编(Assembly)**:GCC将汇编代码转换为机器码,这一步会考虑目标架构的特性。 6. **链接(Linking)**:最后,GCC将编译后的对象文件与库链接起来,形成可执行文件。`-l` 选项用于链接特定的库,如`-lm` ...

    ARM和C语言混编实现随机数的加减

    2. **Output**:这部分定义了内联汇编的输出,即哪些变量被汇编代码更新。例如,通过`"=r" (variable)`告诉编译器将结果存储在特定的通用寄存器中。 3. **Input**:输入部分定义了汇编代码使用的外部变量或值。类似...

Global site tag (gtag.js) - Google Analytics