• 用实例理解c语言的多参数传递过程



    int test_va_arg()
    {
        char str[4+1] = {0};

        char argv1[4+1]  = {'1', '1', '1', '1', 0};
        char argv2[4+1]  = {'2', '2', '2', '2', 0};
        char argv3[4+1]  = {'3', '3', '3', '3', 0};
        char argv4[4+1]  = {'4', '4', '4', '4', 0};
        char argv5[4+1]  = {'5', '5', '5', '5', 0};
        char argv6[4+1]  = {'6', '6', '6', '6', 0};
        char argv7[4+1]  = {'7', '7', '7', '7', 0};
        char argv8[4+1]  = {'8', '8', '8', '8', 0};
        char argv9[4+1]  = {'9', '9', '9', '9', 0};
        char argv10[4+1] = {'a', 'a', 'a', 'a', 0};

        
        strcpy(str,"INFO");
        //tLog( str, argv1, argv2, argv3, argv4, argv5, argv6, argv7, argv8, argv9, argv10 ); 
        //tLog1( str, argv1, argv2, argv3, argv4, argv5, argv6, argv7, argv8, argv9, argv10 ); 

        strcpy( (void *)0x42000200, (const char *)"xoutputx: %s.\n" );


        
        fuck_log1( str, argv1, argv2, argv3, argv4, argv5, argv6, argv7, argv8, argv9, argv10 );

        //tLog1( str, argv1, argv2, argv3, argv4, argv5, argv6, argv7, argv8, argv9, argv10 );
        

        
        return 0;
    }

    /* SPDX-License-Identifier: GPL-2.0+ */
    /*
     * relocate - common relocation function for AArch64 U-Boot
     *
     * (C) Copyright 2013
     * Albert ARIBAUD
     * David Feng
     */

    #include
    #include
    #include
    #include
    #include


    ENTRY( fuck_code )
        LDR    X10, =0x42000000
        STR    X10, [X10, #0x00]
                    
        STP    X29, X30, [SP,#-0x100]!
        MOV    X29, SP
        STR    X19, [SP,#0x10]
                
        MOV    W0, #0xFFFFFFf8
        STR    W0, [X29,#0x38]
        LDR    W1, [X29,#0x38]
        LDR    X0, [X29,#0x20]

        STR    w1, [X10, #0x08]
        TBZ    W1, #0x1F, loc_3718a


        ADD    W2, W1, #8
        CMP    W2, #0
        STR    W2, [X29,#0x38]
        STR    w1, [X10, #0x10]

        ADD    W2, W2, #3

        STR    w2, [X10, #0x18]
        B.LE   loc_3728a

    loc_3718a:    
        LDR    X4, =0x1234
        B      quit    
    loc_3728a:
        LDR    X4, =0x55aa     
    quit:  
        STR    X4, [X10, #0xf0]

        LDR    X19, [SP,#0x10]
        LDP    X29, X30, [SP],#0x100
        ret
    ENDPROC(fuck_code)

    ENTRY( fuck_log1 )           
        STP             X29, X30, [SP,#-0x100]!
        //变量sp+0x00  存储 X29, X30 的原始值
        MOV             X29, SP
        LDR    X10, =0x42000000
        STR    X10, [x10, #0x00]
              
        ADD             X0,  X29, #0x100   
        //x0 栈顶指针 指向函数调用之前的堆栈sp
        //函数的参数如果是8个以内(包含8个) 用x0-x7来传递  (param0-param7)
        //超过8个的部分 从此sp开始依次先储存好 比如超过3个
        //sp+0x00->param8 sp+0x08->param9 sp+0x10->param10

        STR             X19, [SP,#0x10]
        //变量sp+0x10  存储 x19 的原始值
        ldr             X19, =0x42000200   //"xoutputx: %s.\n" printf的第一个参数 x0

        mov    X11, X0
        STR    X11, [x10, #0x08]                                  
        ldr    X12, [X11]
        STR    X12, [x10, #0x10] 
        
        add    X11, x11, #0x08
        STR    X11, [x10, #0x18]
        ldr    X12, [X11]
        STR    X12, [x10, #0x20] 
        
        add    X11, x11, #0x08
        STR    X11, [x10, #0x28]
        ldr    X12, [X11]
        STR    X12, [x10, #0x30] 
        
        add    X11, x11, #0x08
        STR    X11, [x10, #0x38]
        ldr    X12, [X11]
        STR    X12, [x10, #0x40] 

        //add    X11, x11, #0x08
        STR    X7, [x10, #0x48]
        ldr    X12, [X7]
        STR    X12, [x10, #0x50] 

        STR    X6, [x10, #0x58]
        ldr    X12, [X6]
        STR    X12, [x10, #0x60] 

        

        STP             X0, X0, [X29, #0x20] 
        //变量sp+0x20 sp+0x28 存储 x0 栈顶指针

        ADD             X0, X29, #0xC0
        STR             X0, [X29,#0x30]
        //变量sp+0x30 = sp+0xc0

        MOV             W0, #0xFFFFFFC8
        STR             W0, [X29,#0x38]
        //变量sp+0x38 = 0xFFFFFFC8  4字节

        MOV             W0, #0xFFFFFF80
        STR             W0, [X29,#0x3C]
        //变量sp+0x3C = 0xFFFFFF80  4字节

           
        STP             X1, X2, [X29,#0xC8] 
        STP             X3, X4, [X29,#0xD8]
        STP             X5, X6, [X29,#0xE8]
        STR             X7, [X29,#0xF8]
        //传递进来的参数 依次压入堆栈 x1-x7 c8-d8-e8-f8-0x100-[x0 栈顶指针的位置]


        STR             Q0, [X29,#0x40]
        STR             Q1, [X29,#0x50]
        STR             Q2, [X29,#0x60]
        STR             Q3, [X29,#0x70]
        STR             Q4, [X29,#0x80]
        STR             Q5, [X29,#0x90]
        STR             Q6, [X29,#0xA0]
        STR             Q7, [X29,#0xB0]
        //0x40-0xc0 用0填充这块区域 没有用到

    loc_36FC:
        LDR             W1, [X29,#0x38]
        //变量sp+0x38 = 0xFFFFFFC8  4字节
        LDR             X0, [X29,#0x20]
        //栈顶指针
        TBZ             W1, #0x1F, loc_3718
        //测试 sp+0x38 0xFFFFFFC8 & 0x1F 是否等于0,等于0的话跳转到loc_3718
        //否则执行下一条指令
        ADD             W2, W1, #8
        //[sp+0x38] & 0x1f 不等于0, 自加8 
        CMP             W2, #0
        STR             W2, [X29,#0x38]
        B.LE            loc_3728
        //不等于0 跳转

    loc_3718:     
        //等于0 说明经过7次循环 x1-x7已经用完了 
        ADD             X1, X0, #0xF
        AND             X1, X1, #0xFFFFFFFFFFFFFFF8
        STR             X1, [X29,#0x20]
        B               loc_3730

    loc_3728:                                
        LDR             X0, [X29,#0x28]
        //sp+0x28 存储 x0 栈顶指针
        ADD             X0, X0, W1,SXTW
        //x0+w1 w1符号扩展 此例是一个负数 
        //传递进来的参数 依次压入堆栈 x1-x7 c8-d8-e8-f8-0x100-[x0 栈顶指针的位置]
        //栈顶指针的位置 + 负数 精确计算好了 第一次是定位到 x1 
        //7*8=56 0x38 0xFFFFFFC8 + 0x38 = 0x00000000 即-0x38
        //下一次循环就是 -0x30 总共循环7次

    loc_3730:                              
        LDR             X1, [X0]
        //取得压入堆栈的x1的值 第二次是x2 ...
        CBZ             X1, loc_3744
        //等于空退出函数
        MOV             X0, X19 
        BL              printf
        B               loc_36FC

    loc_3744:                              
        LDR             X19, [SP,#0x10]
        //变量sp+0x10   恢复 x19 的原始值
        LDP             X29, X30, [SP],#0x100
        //恢复 X29, X30 的原始值,sp堆栈平衡
        RET
        //程序返回
        
    ENDPROC(fuck_log1)

    IDA伪C码:

    __int64 *__fastcall fuck_log1(long double a1, long double a2, long double a3, long double a4, long double a5, long double a6, long double a7, long double a8, __int64 a9, __int64 a10, __int64 a11, __int64 a12, __int64 a13, __int64 a14, _QWORD *a15, _QWORD *a16, __int64 a17, __int64 a18, __int64 a19, __int64 a20)
    {
      int v20; // w1
      __int64 *result; // x0
      __int64 *v22; // [xsp+20h] [xbp+20h]
      int v23; // [xsp+38h] [xbp+38h]

      MEMORY[0x42000000] = 0x42000000LL;
      MEMORY[0x42000008] = &a17;
      MEMORY[0x42000010] = a17;
      MEMORY[0x42000018] = &a18;
      MEMORY[0x42000020] = a18;
      MEMORY[0x42000028] = &a19;
      MEMORY[0x42000030] = a19;
      MEMORY[0x42000038] = &a20;
      MEMORY[0x42000040] = a20;
      MEMORY[0x42000048] = a16;
      MEMORY[0x42000050] = *a16;
      MEMORY[0x42000058] = a15;
      MEMORY[0x42000060] = *a15;
      v22 = &a17;
      v23 = -56;
      while ( 1 )
      {
        v20 = v23;
        result = v22;
        if ( (v23 & 0x80000000) != 0 && (v23 += 8, v20 + 8 <= 0) )
          result = (__int64 *)((char *)&a17 + v20);
        else
          v22 = (__int64 *)(((unsigned __int64)v22 + 15) & 0xFFFFFFFFFFFFFFF8LL);
        if ( !*result )
          break;
        printf((const unsigned __int8 *)0x42000200);
      }
      return result;
    }

    原始c码:


    void tLog1(char *sInfo, ...)
    {
        char *str   = NULL;
        char *str1 = NULL;
        char *str2 = NULL;
        va_list sArgv;          // 申请参数列表变量
        va_start(sArgv, sInfo); // 申明最后一个传递给函数的已知的固定参数
        /* 依次读取固定参数 sInfo 后的 参数 */

        while(1){
          str  = va_arg(sArgv, char*);
          if( str ){  
              printf("output: %s \n", str );
          }else{
              break;  
          }
        }
        va_end(sArgv);
    }

  • 相关阅读:
    Kubernetes — Calico
    凭什么测试/开发程序员工资那么高?
    Vscode配置已有工程及自动格式化
    事务+事务并发+事务隔离级别【Interview Question】
    集合-set系列集合
    Acwing-Hankson的趣味题-(dfs求因子+质数,因子,数字大小的各种关系的整理)
    十一、MySql的事务(上)
    【C++入门】结构体
    产品经理如何做数据分析
    面试官:React怎么做性能优化
  • 原文地址:https://blog.csdn.net/dp__mcu/article/details/132926020