您的位置:首页 > 编程语言

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

2012-07-09 04:27 896 查看

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                                                                                                                                                                                         
int main() {
    int a = 19, b = 100;
    __asm__ (
        "addl %1, %0;"
        : //no output
        : "a"(a), "b"(b)
        : "%eax", "%ebx"
    );  
    return 0;
}
_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                                                                                                                                                                                         
int main() {
    int a = 17, b = 100;
    __asm__ (
        "addl %2, %1;"
        : "=m"(a)
        : "m"(a), "b"(b)
        : "memory", "%ebx"
    );  
    printf("%d\n", a); 
    return 0;
}
生成的汇编代码的主要部分如下:
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-
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: