zoukankan      html  css  js  c++  java
  • 汇编:普通的函数调用的汇编代码解析

    C代码:

    #include <stdio.h>
    int show()
    {
        return 0 ;
    }
    
    void say()
    {
    }
    int main( )
    {
        show();
        say(); 
        return 0;
    }

    汇编:

    root@ubuntu:/work/demo/demo# arm-linux-gcc -v
    ...............
    gcc version 3.4.5
    
    root@ubuntu:/work/demo/demo# arm-linux-gcc -S demo.c
    root@ubuntu:/work/demo/demo# cat demo.s
        .file    "demo.c"
        .text
        .align    2
        .global    show
        .type    show, %function
    show:
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 1, uses_anonymous_args = 0
        mov    ip, sp
        stmfd    sp!, {fp, ip, lr, pc}
        sub    fp, ip, #4
        mov    r3, #0
        mov    r0, r3       //r0~r3 
        ldmfd    sp, {fp, sp, pc}
        .size    show, .-show
        .align    2
        .global    say
        .type    say, %function
    say:
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 1, uses_anonymous_args = 0
        mov    ip, sp
        stmfd    sp!, {fp, ip, lr, pc}
        sub    fp, ip, #4
        ldmfd    sp, {fp, sp, pc}
        .size    say, .-say
        .align    2
        .global    main
        .type    main, %function
    main:
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 1, uses_anonymous_args = 0
        mov    ip, sp            ;ip = sp
        stmfd    sp!, {fp, ip, lr, pc}    
    ; ! 表示更新基址寄存器。这里表示将寄存器组{fp,ip,lr,pc}中的内容保存到堆栈中,并更新堆栈指针寄存器。
    ; 《ARM处理器开发详解.刘洪涛》P51 P53 P54讲的Arm处理器指令寻址方式,按类描述了各种指令语法格式的含义,并在后面对个指令进行了相信介绍。 sub fp, ip, #
    4      ;fp = ip -4
    bl show bl say mov r3, #0 mov r0, r3 ldmfd sp, {fp, sp, pc} .size main, .-main .ident "GCC: (GNU) 3.4.5"

     arm s3c2440使用满递减栈,sp指向栈顶,堆栈向内存地址减小的地方生长。

     函数一级调用堆栈push/pop图:

    STMFD和LDMFD的原理[4][5]

      在数据栈操作中,

      ldmfd对应通常寻址方式的ldmia;  increase after

      stmfd对应通常寻址模式的stmdb;decrease before

      指令格式 ldm/stm{<cond>} <addressing_mode> <Rn>{!},<reglist>{^}

    stmfd sp!,{r0-r7,pc} 伪代码:
    
    start_addr= Rn - (n_regs*4);
    end_addr = Rn - 4
    if( ConditionPassed(cond) && w==1 )  //w表示指令执行后,基址寄存器是否更新。就是那个!号。
    {
      addr = start_addr;
      for(i=0 to 15)
      {
        if(reglist[i]==True)
        { //在列表内
          *addr = Ri ; //这里Memory是stack,把Ri的数据传输到Memory中。
          addr +=4;
        }
      }
    }
    ldm{<cond>} <addressing_mode> <Rn>{!},<reglist>{^}
    ldmfd (ldmia)伪代码:每次传送后加4.
    ldmfd sp!,{r0-r7,pc}伪代码:
    
    start_addr = Rn
    end_addr = Rn +(n_regs*4)-4
    
    if(ConditionPassed(cond)){//addr表示当前地址。
      addr = start_addr;
      for(i=0 to 15){
        if(reglist[i]==True){
          Ri = *addr 
          addr += 4;
        }
      }
    }
    
    

    参考:

    1.Procedure Call Standard for the ARM® Architecture

    http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf

    2.理解APCS-- ARM过程调用标准

    http://blog.csdn.net/keyboardota/article/details/6799054

    3.Uboot中start.S源码的指令级的详尽解析

    http://www.crifan.com/files/doc/docbook/uboot_starts_analysis/release/htmls/index.html

    4.指令STMFD和LDMFD分析
    http://blog.csdn.net/chuchuanchuan/article/details/8098987
    5.《arm体系结构与编程》.杜春雷

    ++1 、 C函数的汇编解析,C函数参数多于四个的情况:

    //cadd.c
    
    int add(int a, int b, int c, int d, int e)
    {
        return a+b+c+d+e;
    }
    
    int func_add(int a,int b, int c, int d, int e)
    {
        return add(a, b, c, d, e);
    }
    int main()
    {
        int a = 1;    
        int b = 2;
        int c = 3;
        int d = 4;
        int e = 5;
        func_add(a,b,c,d,e);
        
        return 0;
    }
    root@ubuntu:/work/demo/casm# arm-linux-gcc -S  cadd.c 
    root@ubuntu:/work/demo/casm# cat cadd.s
        .file    "cadd.c"
        .text
        .align    2
        .global    add
        .type    add, %function
    add:
        @ args = 4, pretend = 0, frame = 16
        @ frame_needed = 1, uses_anonymous_args = 0
        mov    ip, sp
        stmfd    sp!, {fp, ip, lr, pc}
        sub    fp, ip, #4
        sub    sp, sp, #16
        str    r0, [fp, #-16]
        str    r1, [fp, #-20]
        str    r2, [fp, #-24]
        str    r3, [fp, #-28]
        ldr    r2, [fp, #-16]
        ldr    r3, [fp, #-20]
        add    r3, r2, r3
        ldr    r2, [fp, #-24]
        add    r3, r3, r2
        ldr    r2, [fp, #-28]
        add    r3, r3, r2
        ldr    r2, [fp, #4]
        add    r3, r3, r2
        mov    r0, r3
        sub    sp, fp, #12
        ldmfd    sp, {fp, sp, pc}
        .size    add, .-add
        .align    2
        .global    func_add
        .type    func_add, %function
    func_add:
        @ args = 4, pretend = 0, frame = 16
        @ frame_needed = 1, uses_anonymous_args = 0
        mov    ip, sp
        stmfd    sp!, {fp, ip, lr, pc}
        sub    fp, ip, #4
        sub    sp, sp, #20
        str    r0, [fp, #-16]
        str    r1, [fp, #-20]
        str    r2, [fp, #-24]
        str    r3, [fp, #-28]
        ldr    r3, [fp, #4]
        str    r3, [sp, #0]
        ldr    r0, [fp, #-16]
        ldr    r1, [fp, #-20]
        ldr    r2, [fp, #-24]
        ldr    r3, [fp, #-28]
        bl    add
        mov    r3, r0
        mov    r0, r3
        sub    sp, fp, #12
        ldmfd    sp, {fp, sp, pc}
        .size    func_add, .-func_add
        .align    2
        .global    main
        .type    main, %function
    main:
        @ args = 0, pretend = 0, frame = 20
        @ frame_needed = 1, uses_anonymous_args = 0
        mov    ip, sp
        stmfd    sp!, {fp, ip, lr, pc}
        sub    fp, ip, #4
        sub    sp, sp, #24
        mov    r3, #1
        str    r3, [fp, #-16]
        mov    r3, #2
        str    r3, [fp, #-20]
        mov    r3, #3
        str    r3, [fp, #-24]
        mov    r3, #4
        str    r3, [fp, #-28]
        mov    r3, #5
        str    r3, [fp, #-32]
        ldr    r3, [fp, #-32]
        str    r3, [sp, #0]
        ldr    r0, [fp, #-16]
        ldr    r1, [fp, #-20]
        ldr    r2, [fp, #-24]
        ldr    r3, [fp, #-28]
        bl    func_add
        mov    r3, #0
        mov    r0, r3
        sub    sp, fp, #12
        ldmfd    sp, {fp, sp, pc}
        
        .size    main, .-main
        .ident    "GCC: (GNU) 3.4.5"

    ++2 、下面再看如果用某个函数的返回值做为函数的参数,传参次序会不会不一样:

    ++3、上面的例子没有说明多个参数在栈中的存取次序是怎样的。

    下面的例子来补充说明。

  • 相关阅读:
    -webkit-margin-before 及 扩展浏览器前缀、内核
    vue封装分页组件
    vue项目中使用qrcode生成二维码
    git中全局设置用户名、邮箱
    promise.all 解说
    超详细弹性盒子布局
    js对象转数组
    js取整数、取余数的方法
    数组方法大全
    Vue绑定class
  • 原文地址:https://www.cnblogs.com/mylinux/p/4139972.html
Copyright © 2011-2022 走看看