zoukankan      html  css  js  c++  java
  • c、数组与汇编

      上次的“c调用汇编”使用的clang编译器,而且使用的是mac 64位系统。当时感觉写的汇编怪怪的,

    今天闲来无事,就在w7 32位系统下把c文件汇编后,确实与mac后的差异很大。

    可不仅仅是寄存器eax与rax的区别。我想说的是函数参数传递的不同。mac下clang编译后

    函数的参数先保存在寄存器中(以一定的规则保存),然后在函数中压入栈里,

    以待后用。例如上篇例子,红色部分:

    .global _decToBin 
     
     _decToBin:
         pushq     %rbp
         movq    %rsp,%rbp
     
         movq     %rdi,-8(%rbp) #第一个参数,保存在rdi中
         movq     %rsi,-16(%rbp) #第二个参数,保存在rsi中
     
         movq    -8(%rbp),%rax
         movq    -16(%rbp),%rbx
         movq    $63,%rcx
     
    ......
     
         popq     %rbp
         ret

    而我在w7下使用cygwin安装的gcc编译test.c文件:

    test.c:

    int hello(int a,int b,int c,int d)
    {
        return b;
    }

    test.s:

        .file    "test.c"
        .text
        .globl    _hello
        .def    _hello;    .scl    2;    .type    32;    .endef
    _hello:
        pushl    %ebp
        movl    %esp, %ebp
        movl    12(%ebp), %eax #说明参数是函数在使用其值之前就已经压入栈中
        popl    %ebp
        ret

    这说明clang与gcc使用了两种不同的规则(网上有很多介绍函数值传递的不同规则的,我就不介绍了)。

    所以不同的平台不同的编译器要不同的对待。以上算是上次的不足补充吧。

    下面来看看数组:

    test.c例子:

     1 void hello1()
     2 {
     3     int a[3]={1,2,3};
     4         int b=a[1];
     5 }
     6 void hello2()
     7 {
     8     int a[3]={1,2,3};
     9     int b=*(a+1);
    10 } 
    11 void hello3()
    12 {
    13     int a[3]={1,2,3};
    14     int b=1[a]; //这也对?
    15 }           

    如果看的够仔细的话,三个函数没什么不同就是对数组a[1]的不同(当然函数名除外).

    gcc -S test.c 后:

     1     .file    "test.c"
     2     .data
     3     .align 4
     4 LC0:
     5     .long    1
     6     .long    2
     7     .long    3
     8     .text
     9     .globl    _hello1
    10     .def    _hello1;    .scl    2;    .type    32;    .endef
    11 _hello1:
    12     pushl    %ebp
    13     movl    %esp, %ebp
    14     pushl    %edi
    15     pushl    %esi
    16     pushl    %ebx
    17     subl    $16, %esp
    18     leal    -28(%ebp), %edx
    19     movl    $LC0, %ebx
    20     movl    $3, %eax
    21     movl    %edx, %edi
    22     movl    %ebx, %esi
    23     movl    %eax, %ecx
    24     rep movsl
    25     movl    -24(%ebp), %eax
    26     movl    %eax, -16(%ebp)
    27     addl    $16, %esp
    28     popl    %ebx
    29     popl    %esi
    30     popl    %edi
    31     popl    %ebp
    32     ret
    33     .globl    _hello2
    34     .def    _hello2;    .scl    2;    .type    32;    .endef
    35 _hello2:
    36     pushl    %ebp
    37     movl    %esp, %ebp
    38     pushl    %edi
    39     pushl    %esi
    40     pushl    %ebx
    41     subl    $16, %esp
    42     leal    -28(%ebp), %edx
    43     movl    $LC0, %ebx
    44     movl    $3, %eax
    45     movl    %edx, %edi
    46     movl    %ebx, %esi
    47     movl    %eax, %ecx
    48     rep movsl
    49     leal    -28(%ebp), %eax
    50     movl    4(%eax), %eax
    51     movl    %eax, -16(%ebp)
    52     addl    $16, %esp
    53     popl    %ebx
    54     popl    %esi
    55     popl    %edi
    56     popl    %ebp
    57     ret
    58     .globl    _hello3
    59     .def    _hello3;    .scl    2;    .type    32;    .endef
    60 _hello3:
    61     pushl    %ebp
    62     movl    %esp, %ebp
    63     pushl    %edi
    64     pushl    %esi
    65     pushl    %ebx
    66     subl    $16, %esp
    67     leal    -28(%ebp), %edx
    68     movl    $LC0, %ebx
    69     movl    $3, %eax
    70     movl    %edx, %edi
    71     movl    %ebx, %esi
    72     movl    %eax, %ecx
    73     rep movsl
    74     movl    -24(%ebp), %eax
    75     movl    %eax, -16(%ebp)
    76     addl    $16, %esp
    77     popl    %ebx
    78     popl    %esi
    79     popl    %edi
    80     popl    %ebp
    81     ret

    只要看红色的行,我们可以看到25-27行与74-76行一样,说明hello1与hello3没什么不同,

    效率一样。而49-52行比他们多了一行,所以*(a+1)比a[1]和1[a]要低一点。

     但是我们看下面的例子。

    test1.c与test2.c:

    View Code
     //1--------------
    #include <stdlib.h>
    void hello()
    {
        int *a=(int*)malloc(sizeof(int)*3);
        int b=*(a+1);
        free(a);
    }
    
     //2--------------
    #include <stdlib.h>
    void hello()
    {
        int *a=(int*)malloc(sizeof(int)*3);
        int b=a[1];
        free(a);
    }

    汇编后完全一样:

    View Code
     1     .file    "main.c"
     2     .text
     3     .globl    _hello
     4     .def    _hello;    .scl    2;    .type    32;    .endef
     5 _hello:
     6     pushl    %ebp
     7     movl    %esp, %ebp
     8     subl    $40, %esp
     9     movl    $12, (%esp)
    10     call    _malloc
    11     movl    %eax, -12(%ebp)
    12     movl    -12(%ebp), %eax
    13     movl    4(%eax), %eax
    14     movl    %eax, -16(%ebp)
    15     leave
    16     ret
    17     .def    _malloc;    .scl    2;    .type    32;    .endef

      所以在堆中使用*(a+n)与a[n]没什么不同,只用在栈中才会有所不同。

      学习汇编不是必要,但是它可以让我们知道效率。

  • 相关阅读:
    Redis基础
    Windows 10 中 安装 RabbitMQ
    Nginx
    第二章-矩阵
    第一章-行列式
    第六章-微分方程
    第五章-多元函数
    第四章-定积分
    第三章-不定积分
    第二章-导数
  • 原文地址:https://www.cnblogs.com/wuchaofan/p/3031749.html
Copyright © 2011-2022 走看看