测试前,需要了解下sysv的传参方式:
1、输入参数通过r0-r3传递,多余的放入堆栈中;返回值放入r0,不够的话放入{r0,r1}或者{r0,r1,r2,r3},比如:
int foo(int a, int b, int c, int d), 输入:r0 = a, r1 = b, r2 = c, r3 = d,返回:r0 = 类型为int的retvalue
int *foo(char a, double b, int c, char d), 输入:r0 = a, r1用于对齐(double 要求8字节对齐), b = {r2, r3},c放在堆栈的sp[0]位置,d放在堆栈的sp[4]位置,这里的sp是指进入函数时的sp;返回:r0 = 类型为int *的retvalue
2、注意如果返回值是结构体,情况有些特殊:
struct client foo(int a, char b, float c), 输入:r0 = 一个strcut client *变量,由调用者给出, r1 = a, r2 = b, r3 = c;返回:strcut client *变量,和调用者给的一样

为了测试arm平台函数参数如何对齐,多余参数如何传递,以及如何返回一个结构体类型的变量,编写如下代码:

#include <stdio.h>
#include <stdlib.h>typedef struct _Foo{int a;char b;double c;float d;
}Foo;Foo test(int a, char b, double c, float d)
{Foo *f = (Foo *)malloc(sizeof(Foo));f->a = a;f->b = b;f->c = c;f->d = d;return *f;
}int main(void)
{Foo retvalue; retvalue = test(1,2,3,4);return retvalue.a;
}

malloc会有内存溢出,这样写是为了反汇编更简单些,编译时不开优化,使用-marm参数指定使用arm指令集,然后反汇编得到:

00000000 <test>:0:   e92d4810    push    {r4, fp, lr}4:   e28db008    add fp, sp, #8  //fp = sp + 88:   e24dd01c    sub sp, sp, #28 //sp = sp -28c:   e50b0018    str r0, [fp, #-24]  ; 0xffffffe8 //fp[-24] = r0 = Foo * temp10:   e50b101c    str r1, [fp, #-28]  ; 0xffffffe4 //fp[-28] = r1 = int a14:   e1a03002    mov r3, r2                       //fp[-29] = r2 = char b, r3 not used18:   e54b301d    strb    r3, [fp, #-29]  ; 0xffffffe31c:   e3a00018    mov r0, #2420:   ebfffffe    bl  0 <malloc>          //malloc(24)24:   e1a03000    mov r3, r0              //r3 = f28:   e50b3010    str r3, [fp, #-16]      //fp[-16] = f2c:   e51b3010    ldr r3, [fp, #-16]      //r3 = f30:   e51b201c    ldr r2, [fp, #-28]  ; 0xffffffe4 //r2 = fp[-28] = int a34:   e5832000    str r2, [r3]                     //f->a = r2 = a38:   e51b3010    ldr r3, [fp, #-16]3c:   e55b201d    ldrb    r2, [fp, #-29]  ; 0xffffffe3 //r2 = fp[-29] = char b40:   e5c32004    strb    r2, [r3, #4]                 //f->b = r2 = b44:   e51b2010    ldr r2, [fp, #-16]                   //r2 = f48:   e99b0018    ldmib   fp, {r3, r4}                //double c = {r3, r4}4c:   e5823008    str r3, [r2, #8]                    //f[8] = r350:   e582400c    str r4, [r2, #12]                   //f[12] = r4, f->c = c54:   e51b3010    ldr r3, [fp, #-16]                  //r3 = f58:   e59b200c    ldr r2, [fp, #12]                   //r2 = float d5c:   e5832010    str r2, [r3, #16]                   //f->d = float d60:   e51b2018    ldr r2, [fp, #-24]  ; 0xffffffe8    //r2 = r0 = Foo *temp64:   e51b3010    ldr r3, [fp, #-16]                  //r3 = f68:   e1a0c002    mov ip, r2                          //ip = r0 = Foo *temp6c:   e1a0e003    mov lr, r3                          //lr = f70:   e8be000f    ldm lr!, {r0, r1, r2, r3}           //拷贝f指向的前16个字节到Foo *temp指向的74:   e8ac000f    stmia   ip!, {r0, r1, r2, r3}78:   e89e0003    ldm lr, {r0, r1}                    //拷贝后面8个字节,加起来=24=sizeof(Foo)7c:   e88c0003    stm ip, {r0, r1}80:   e51b0018    ldr r0, [fp, #-24]  ; 0xffffffe8    //返回r0 = Foo *temp84:   e24bd008    sub sp, fp, #888:   e8bd8810    pop {r4, fp, pc}0000008c <main>:8c:   e92d4810        push    {r4, fp, lr}90:   e28db008        add     fp, sp, #8                  //fp = sp + 894:   e24dd02c        sub     sp, sp, #44     ; 0x2c      //sp = sp - 4498:   e24b0024        sub     r0, fp, #36     ; 0x24      //r0 = fp - 36 = &retvalue = Foo *temp9c:   e59f3028        ldr     r3, [pc, #40]   ; cc <main+0x40>a0:   e58d3008        str     r3, [sp, #8]                //float d, 放入堆栈a4:   e3a03000        mov     r3, #0a8:   e59f4020        ldr     r4, [pc, #32]   ; d0 <main+0x44>ac:   e88d0018        stm     sp, {r3, r4}                //double c, 放入堆栈b0:   e3a02002        mov     r2, #2                      //b = 2b4:   e3a01001        mov     r1, #1                      //a = 1b8:   ebfffffe        bl      0 <test>bc:   e51b3024        ldr     r3, [fp, #-36]  ; 0xffffffdc //r3 = retvalue.ac0:   e1a00003        mov     r0, r3                      //r0 = r3 = retvalue.a,main返回值c4:   e24bd008        sub     sp, fp, #8c8:   e8bd8810        pop     {r4, fp, pc}cc:   40800000        .word   0x40800000d0:   40080000        .word   0x40080000

重点分析test函数,它的参数为:

r0: struct Foo *temp,通过main函数传递过来的,用于存放struct Foo结构体
r1: int a
r2: char b, 即使是char,也独立占一个寄存器,不与其他参数共用寄存器
r3: for alignment,下一个参数是double,要求对齐为8
c: sp[0-7],多余的参数放在堆栈上,这里是double c
d: sp[8-11],float d

test函数的堆栈结构为:

下面,逐行分析test的汇编代码,来验证上述内容。

1、进入test函数时,sp指向double c的低四字节,然后push {r4, fp, lr}之后,sp指向保存r4的位置:

   0:   e92d4810    push    {r4, fp, lr}

2、fp=sp+8, sp=sp-28:

   4:   e28db008    add fp, sp, #8  //fp = sp + 88:   e24dd01c    sub sp, sp, #28 //sp = sp -28

3、把struct Foo *temp,也就是r0,存到fp-24的位置上:

   c:   e50b0018    str r0, [fp, #-24]  ; 0xffffffe8 //fp[-24] = r0 = Foo *temp

4、把int a,也就是r1,存到fp-28的位置上:

  10:   e50b101c    str r1, [fp, #-28]  ; 0xffffffe4 //fp[-28] = r1 = int a 

5、把char b,也就是r2,存到fp-29的位置上,注意只放了一个字节,还剩下三个字节没有使用;注意r3没有有效值,只是为了对齐的,所以可以直接覆盖:

  14:   e1a03002    mov r3, r2                       //fp[-29] = r2 = char b, r3 not used18:   e54b301d    strb    r3, [fp, #-29]  ; 0xffffffe3

6、至此,输入参数已全部保存在堆栈上(double c, float d, 一开始就在堆栈高地址上)

7、调用malloc(24)函数,因为sizeof(Foo)=24,返回值r0赋值给r3,保存在fp-16位置,也就是变量Foo *f:

  1c:   e3a00018    mov r0, #2420:   ebfffffe    bl  0 <malloc>          //malloc(24)24:   e1a03000    mov r3, r0              //r3 = f28:   e50b3010    str r3, [fp, #-16]      //fp[-16] = f2c:   e51b3010    ldr r3, [fp, #-16]      //r3 = f

8、从fp-28取出int a,保存到f+0位置上,也就是f->a=a:

  30:   e51b201c    ldr r2, [fp, #-28]  ; 0xffffffe4 //r2 = fp[-28] = int a34:   e5832000    str r2, [r3]                     //f->a = r2 = a

9、从fp-29取出char b,保存到f+4位置上,也就是f->b=b:

  38:   e51b3010    ldr r3, [fp, #-16]3c:   e55b201d    ldrb    r2, [fp, #-29]  ; 0xffffffe3 //r2 = fp[-29] = char b40:   e5c32004    strb    r2, [r3, #4]                 //f->b = r2 = b

10、ldmib fp, {r3, r4},地址先增加4,然后取值保存到r3,地址再增加4,取值保存到r4,地址值不回写,也就是取出double c,放入r3,r4,然后保存到f+8地址和f+12地址上,也就是f->c=c:

  44:   e51b2010    ldr r2, [fp, #-16]                   //r2 = f48:   e99b0018    ldmib   fp, {r3, r4}                //double c = {r3, r4}4c:   e5823008    str r3, [r2, #8]                    //f[8] = r350:   e582400c    str r4, [r2, #12]                   //f[12] = r4, f->c = c

11、取fp+12位置的float d,保存到f+16地址,也就是f->d=d:

  54:   e51b3010    ldr r3, [fp, #-16]                  //r3 = f58:   e59b200c    ldr r2, [fp, #12]                   //r2 = float d5c:   e5832010    str r2, [r3, #16]                   //f->d = float d

12、ip = Foo * temp = [fp - 24] = r0@entry,lr = f = [fp - 16],从f指向的地址取16字节,保存到ip指向的地址,然后再取8字节,保存到ip指向的地址,也就是按值拷贝f指向的结构体到Foo *temp = r0指向的结构体:

  60:   e51b2018    ldr r2, [fp, #-24]  ; 0xffffffe8    //r2 = r0 = Foo *temp64:   e51b3010    ldr r3, [fp, #-16]                  //r3 = f68:   e1a0c002    mov ip, r2                          //ip = r0 = Foo *temp6c:   e1a0e003    mov lr, r3                          //lr = f70:   e8be000f    ldm lr!, {r0, r1, r2, r3}           //拷贝f指向的前16个字节到r0 = Foo *temp指向的74:   e8ac000f    stmia   ip!, {r0, r1, r2, r3}78:   e89e0003    ldm lr, {r0, r1}                    //拷贝后面8个字节,加起来=24=sizeof(Foo)7c:   e88c0003    stm ip, {r0, r1}

13、设置返回值r0,为Foo *temp,返回:

  80:   e51b0018    ldr r0, [fp, #-24]  ; 0xffffffe8    //返回r0 = Foo *temp84:   e24bd008    sub sp, fp, #888:   e8bd8810    pop {r4, fp, pc}

然后分析main函数

main的堆栈为:

这里的SP=SP-44也就是test函数堆栈的SP@entry

main的汇编代码为:

1、进入函数后,push{r4, fp, lr},sp指向存放r4的位置:

  8c:   e92d4810        push    {r4, fp, lr}

2、fp=sp+8, sp=sp-44:

  90:   e28db008        add     fp, sp, #8                  //fp = sp + 894:   e24dd02c        sub     sp, sp, #44     ; 0x2c      //sp = sp - 44

3、为临时变量Foo retvalue申请内存,&retvalue为r0 = fp-36,也就是传递给test函数的那个Foo *temp:

  98:   e24b0024        sub     r0, fp, #36     ; 0x24      //r0 = fp - 36 = &retvalue = Foo *temp

4、取fload d的输入值,放入sp+8位置:

  9c:   e59f3028        ldr     r3, [pc, #40]   ; cc <main+0x40>a0:   e58d3008        str     r3, [sp, #8]                //float d, 放入堆栈

5、取double c的输入值,放入sp+0位置:

  a4:   e3a03000        mov     r3, #0a8:   e59f4020        ldr     r4, [pc, #32]   ; d0 <main+0x44>ac:   e88d0018        stm     sp, {r3, r4}                //double c, 放入堆栈

6、设置r1 = int a = 1, r2 = char b = 2,注意到r0 = Foo * temp = &retvalue,r3用于对齐,double c 和float d已放入堆栈sp0-sp12的位置上,调用test函数:

  b0:   e3a02002        mov     r2, #2                      //b = 2b4:   e3a01001        mov     r1, #1                      //a = 1b8:   ebfffffe        bl      0 <test>

7、取retvalue.a的值到r3,然后赋值给r0,为函数main的返回值:

  bc:   e51b3024        ldr     r3, [fp, #-36]  ; 0xffffffdc //r3 = retvalue.ac0:   e1a00003        mov     r0, r3                      //r0 = r3 = retvalue.a,main返回值

8、main函数返回:

  c4:   e24bd008        sub     sp, fp, #8c8:   e8bd8810        pop     {r4, fp, pc}cc:   40800000        .word   0x40800000d0:   40080000        .word   0x40080000

arm平台函数传递参数,反汇编实例分析相关推荐

  1. python函数定义与参数_Python函数的定义方式与函数参数问题实例分析

    本文实例讲述了Python函数的定义方式与函数参数问题.分享给大家供大家参考,具体如下: 涉及内容: 函数的定义方式 函数的文字描述 空操作语句 位置参数 默认参数 关键参数 可变长度参数 函数的定义 ...

  2. PHP - 回调函数概念与用法实例分析 - 学习/实践

    1.应用场景 主要用于理解回调函数的概念, 对比JavaScript中的回调函数, 更加深刻理解回调函数的本质, 以及如何高效使用~~~ 2.学习/操作 1. 文档阅读 https://www.jb5 ...

  3. pthread_create函数详解(向线程函数传递参数)

    一.pthread_create函数: 1.简介:pthread_create是UNIX环境创建线程的函数 2.头文件:#include <pthread.h> 3.函数声明: int p ...

  4. python 函数传递参数的多种方法

    python中函数根据是否有返回值可以分为四种:无参数无返回值,无参数有返回值,有参数无返回值,有参数有返回值. Python中函数传递参数的形式主要有以下五种,分别为位置传递,关键字传递,默认值传递 ...

  5. python参数传递方法_深入理解python中函数传递参数是值传递还是引用传递

    python 的 深入理解python中函数传递参数是值传递还是引用传递 目前网络上大部分博客的结论都是这样的: Python不允许程序员选择采用传值还是传 引用.Python参数传递采用的肯定是&q ...

  6. js中函数传递参数,究竟是值传递还是引用传递?

    记住真理: js函数传递参数,不管是简单数据类型,还是引用数据类型,都是值传递!! 下面是js红包书里面的例子: function setName(obj) { obj.name = "Ni ...

  7. linux中probe函数传递参数的寻找(下)

    点击打开链接 linux中probe函数传递参数的寻找(下) 通过追寻driver的脚步,我们有了努力的方向:只有找到spi_bus_type的填充device即可,下面该从device去打通,当两个 ...

  8. C++11向线程函数传递参数

    template< class Function, class... Args > explicit thread( Function&& f, Args&& ...

  9. pthread_create函数的详细讲解(包括向线程函数传递参数详解)

    pthread_create是UNIX环境创建线程函数 头文件 #include<pthread.h> 函数声明 int pthread_create(pthread_t*restrict ...

最新文章

  1. map/reduce的概念
  2. VC++套接字、数据库、文件读写综合应用-客户端读取文件套接字接收服务端写入数据库
  3. Android Material Design TabLayout属性app:tabMode和app: tabGravity
  4. System.getProperty(user.dir)
  5. [JavaScript] - replaceAll,将字符串中的字母或数字等全部替换掉的方式
  6. MAC修改.bashrc/.bash_profile无效,默认的用户配置文件是.zshrc,
  7. 简单的事情搞复杂:挂个版本到网站,拖了几个月还没做
  8. Oracle的exp导出、imp导入数据命令
  9. 光滑曲线_光滑流形初步(2)——切向量与微分
  10. XML 大于号 小于号 处理
  11. asp.net/c# 注册页实现激活邮箱验证
  12. CE修改器入门:寻找指针基址
  13. (私人收藏)2019WER积木教育机器人赛(普及赛)解决方案-(全套)获取能源核心...
  14. 转:数据可视化之美:经典案例与实践解析
  15. Contiki 配置参数“技巧”说明
  16. 麻省理工科技评论:AI预言的七宗罪(上)
  17. mybatis从入门到精通(刘增辉著)-读书笔记第二章
  18. 关于任务规划和提高执行力
  19. 每台计算机用户都有一个独有的,因特网上的每台正式计算机用户都有一个独有的()。A.Mac地址B.网络号C.主机号D.IP地址...
  20. 海思Hi3559AV100移植Qt5.9.1

热门文章

  1. 移动硬盘无法休眠了?
  2. VB获得磁盘的文件系统
  3. 2019ASC世界大学生超算竞赛预赛结果出炉:20校晋级,北航第一
  4. 高通把苹果逼急了?传苹果正大力研发调制解调器
  5. 决不允许AI杀人武器研发!马斯克领衔2400名科学家签署联名宣言
  6. 科大讯飞2017年报:营收54亿利润5.9亿,政府补助1.18亿
  7. 4.5亿!依图的AI芯片计划初步浮出水面
  8. 如何将JavaScript转化成Swift?(二)
  9. logback之使用demo
  10. python获取指定日期的前N天日期和后N天日期