您的位置:首页 > 其它

AAPCS 学习课后练习 - 通过一个小例子来讲解

2015-12-13 15:57 561 查看
一、有个函数有10个参数,请问是参数是如何传递的?请画出压栈图(32位 / 64位).

<1> 首先看ARM32

。编写 test.c

#include <stdio.h>

int func(int v1, int v2, int v3, int v4,
int v5, int v6, int v7, int v8,
int v9, int *p1)
{
int s = 0x1;

s += v1;
s += v2;
s += v3;
s += v4;

s += v5;
s += v6;
s += v7;
s += v8;
s += v9;

s += *p1;

return s;
}

int main( int argc, char **argv)
{
int a = 100;
int t = 10;

t += func(1,2,3,4,5,6,7,8,9,&a);

return t;
}


。编写Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS += -g3 -O0  #取消gcc优化
LOCAL_SRC_FILES := test.c
LOCAL_MODULE := test
include $(BUILD_EXECUTABLE)


。mmm 编译:
Install: out/target/product/${project}/symbol/system/bin/test

。使用objdump工具解开test:

./prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin/arm-linux-androideabi-objdump -S out/target/product/${project}/symbols/system/bin/test >vendor/test/test-arm32.S

#include <stdio.h>
00000398 <func>:
int func(int v1, int v2, int v3, int v4,
int v5, int v6, int v7, int v8,
int v9, int *p1)
{
398:  b086          sub sp, #24        //sp向下偏移24字节
39a:  9003          str r0, [sp, #12]
39c:  9102          str r1, [sp, #8]
39e:  9201          str r2, [sp, #4]
3a0:  9300          str r3, [sp, #0]   //main函数传入的v1-v4参数入栈保存
int s = 0x1;
3a2:  2301          movs    r3, #1
3a4:  9305          str r3, [sp, #20]  //局部变量s入栈保存,执行到此处的压栈如【图5】

s += v1;
3a6:  9a05          ldr r2, [sp, #20]  //依次从栈中取出v1-v4参数值,依次进行累加操作
3a8:  9b03          ldr r3, [sp, #12]
3aa:  4413          add r3, r2
3ac:  9305          str r3, [sp, #20]
s += v2;
3ae:  9a05          ldr r2, [sp, #20]
3b0:  9b02          ldr r3, [sp, #8]
3b2:  4413          add r3, r2
3b4:  9305          str r3, [sp, #20]
s += v3;
3b6:  9a05          ldr r2, [sp, #20]
3b8:  9b01          ldr r3, [sp, #4]
3ba:  4413          add r3, r2
3bc:  9305          str r3, [sp, #20]
s += v4;
3be:  9a05          ldr r2, [sp, #20]
3c0:  9b00          ldr r3, [sp, #0]
3c2:  4413          add r3, r2
3c4:  9305          str r3, [sp, #20]

s += v5;
3c6:  9a05          ldr r2, [sp, #20]  //依次从栈中取出v5-p1参数值进行累计操作
3c8:  9b06          ldr r3, [sp, #24]
3ca:  4413          add r3, r2
3cc:  9305          str r3, [sp, #20]
s += v6;
3ce:  9a05          ldr r2, [sp, #20]
3d0:  9b07          ldr r3, [sp, #28]
3d2:  4413          add r3, r2
3d4:  9305          str r3, [sp, #20]
s += v7;
3d6:  9a05          ldr r2, [sp, #20]
3d8:  9b08          ldr r3, [sp, #32]
3da:  4413          add r3, r2
3dc:  9305          str r3, [sp, #20]
s += v8;
3de:  9a05          ldr r2, [sp, #20]
3e0:  9b09          ldr r3, [sp, #36] ; 0x24
3e2:  4413          add r3, r2
3e4:  9305          str r3, [sp, #20]
s += v9;
3e6:  9a05          ldr r2, [sp, #20]
3e8:  9b0a          ldr r3, [sp, #40] ; 0x28
3ea:  4413          add r3, r2
3ec:  9305          str r3, [sp, #20]

s += *p1;
3ee:  9b0b          ldr r3, [sp, #44] ; 0x2c
3f0:  681b          ldr r3, [r3, #0]
3f2:  9a05          ldr r2, [sp, #20]
3f4:  4413          add r3, r2
3f6:  9305          str r3, [sp, #20]

return s;
3f8:  9b05          ldr r3, [sp, #20]
}
3fa:  4618          mov r0, r3        //计算结果保存到r0,作为子程序返回值
3fc:  b006          add sp, #24       //恢复sp指针
3fe:  4770          bx  lr            //返回main函数

00000400 <main>:

int main( int argc, char **argv)
{
400:  b500          push    {lr}           //lr压栈,lr保存地址:base+4,
//sp指向初始位置地址:sp -> base,此时sp位置如【图1】
402:  b08b          sub sp, #44    ; 0x2c
404:  9007          str r0, [sp, #28]
406:  9106          str r1, [sp, #24]        //sp指针向下移动44字节,sp -> base -44, r0,r1入栈,
//执行到此处压栈 如【图2】
int a = 100;
408:  2364          movs    r3, #100   ; 0x64
40a:  9308          str r3, [sp, #32]
int t = 10;
40c:  230a          movs    r3, #10
40e:  9309          str r3, [sp, #36] ; 0x24  //局部变量a,t 入栈,位置为sp+32,sp+36,
//执行到此处压栈 如【图3】

t += func(1,2,3,4,5,6,7,8,9,&a);            //func子程序有v1-p1共10个参数,
//v1-v4直接使用r0-r3传递,其它通过数据栈传递
410:  2305          movs    r3, #5            //如下v5-p1参数依次压栈,sp偏移分别为 0,4,8,12,16,20
412:  9300          str r3, [sp, #0]
414:  2306          movs    r3, #6
416:  9301          str r3, [sp, #4]
418:  2307          movs    r3, #7
41a:  9302          str r3, [sp, #8]
41c:  2308          movs    r3, #8
41e:  9303          str r3, [sp, #12]
420:  2309          movs    r3, #9
422:  9304          str r3, [sp, #16]
424:  ab08          add r3, sp, #32
426:  9305          str r3, [sp, #20]         //v5-p1参数压栈完毕,子程序通过栈获取参数.
428:  2001          movs    r0, #1
42a:  2102          movs    r1, #2
42c:  2203          movs    r2, #3
42e:  2304          movs    r3, #4            //v1-v4参数依次保存到r0-r3完毕,直接传入func子程序.
//执行到此处压栈 如【图4】
430:  f7ff ffb2     bl  398 <func>            //跳转到func子程序
434:  4603          mov r3, r0                //func函数返回值保持在r0
436:  9a09          ldr r2, [sp, #36] ; 0x24
438:  4413          add r3, r2
43a:  9309          str r3, [sp, #36] ; 0x24

return t;
43c:  9b09          ldr r3, [sp, #36] ; 0x24
}
43e:  4618          mov r0, r3                //main函数返回值保存在r0
440:  b00b          add sp, #44    ; 0x2c     //恢复sp指针,回到【图1】
442:  f85d fb04     ldr.w   pc, [sp], #4      //从lr(base+4)恢复pc指针
446:  bf00          nop


。v1-v4使用r0-r3直接传入子程序

。v5-p1使用压栈方式传入,子程序结果返回值存于r0

。局部变量压栈保存,需要使用时候再从栈弹出

压栈图







<1> 再看 ARM64

。在64位环境编译test.c, 使用objdump工具解开test

(mmm vendor/test/;aarch64-linux-android-objdump -S out/target/product/p6601/symbols/system/bin/test >vendor/test/test-arm64.S)

0000000000000628 <func>:               //子程序分析和arm32类似,此处省略100字...
#include <stdio.h>

int func(int v1, int v2, int v3, int v4,
int v5, int v6, int v7, int v8,
int v9, int *p1)
{
628:  d100c3ff   sub sp, sp, #0x30
62c:  b9001fe0   str w0, [sp,#28]
630:  b9001be1   str w1, [sp,#24]
634:  b90017e2   str w2, [sp,#20]
638:  b90013e3   str w3, [sp,#16]
63c:  b9000fe4   str w4, [sp,#12]
640:  b9000be5   str w5, [sp,#8]
644:  b90007e6   str w6, [sp,#4]
648:  b90003e7   str w7, [sp]
int s = 0x1;
64c:  52800020   mov w0, #0x1                    // #1
650:  b9002fe0   str w0, [sp,#44]

s += v1;
654:  b9402fe1   ldr w1, [sp,#44]
658:  b9401fe0   ldr w0, [sp,#28]
65c:  0b000020   add w0, w1, w0
660:  b9002fe0   str w0, [sp,#44]
s += v2;
664:  b9402fe1   ldr w1, [sp,#44]
668:  b9401be0   ldr w0, [sp,#24]
66c:  0b000020   add w0, w1, w0
670:  b9002fe0   str w0, [sp,#44]
s += v3;
674:  b9402fe1   ldr w1, [sp,#44]
678:  b94017e0   ldr w0, [sp,#20]
67c:  0b000020   add w0, w1, w0
680:  b9002fe0   str w0, [sp,#44]
s += v4;
684:  b9402fe1   ldr w1, [sp,#44]
688:  b94013e0   ldr w0, [sp,#16]
68c:  0b000020   add w0, w1, w0
690:  b9002fe0   str w0, [sp,#44]

s += v5;
694:  b9402fe1   ldr w1, [sp,#44]
698:  b9400fe0   ldr w0, [sp,#12]
69c:  0b000020   add w0, w1, w0
6a0:  b9002fe0   str w0, [sp,#44]
s += v6;
6a4:  b9402fe1   ldr w1, [sp,#44]
6a8:  b9400be0   ldr w0, [sp,#8]
6ac:  0b000020   add w0, w1, w0
6b0:  b9002fe0   str w0, [sp,#44]
s += v7;
6b4:  b9402fe1   ldr w1, [sp,#44]
6b8:  b94007e0   ldr w0, [sp,#4]
6bc:  0b000020   add w0, w1, w0
6c0:  b9002fe0   str w0, [sp,#44]
s += v8;
6c4:  b9402fe1   ldr w1, [sp,#44]
6c8:  b94003e0   ldr w0, [sp]
6cc:  0b000020   add w0, w1, w0
6d0:  b9002fe0   str w0, [sp,#44]
s += v9;
6d4:  b9402fe1   ldr w1, [sp,#44]
6d8:  b94033e0   ldr w0, [sp,#48]
6dc:  0b000020   add w0, w1, w0
6e0:  b9002fe0   str w0, [sp,#44]

s += *p1;
6e4:  f9401fe0   ldr x0, [sp,#56]
6e8:  b9400000   ldr w0, [x0]
6ec:  b9402fe1   ldr w1, [sp,#44]
6f0:  0b000020   add w0, w1, w0
6f4:  b9002fe0   str w0, [sp,#44]

return s;
6f8:  b9402fe0   ldr w0, [sp,#44]
}
6fc:  9100c3ff   add sp, sp, #0x30
700:  d65f03c0   ret

0000000000000704 <main>:

int main( int argc, char **argv)
{
704:  d10103ff   sub sp, sp, #0x40       //sp向下偏移64字节,sp = base -64;
708:  a9017bfd   stp x29, x30, [sp,#16]  //x29,x30(lr)压栈保存
70c:  910043fd   add x29, sp, #0x10      //x29 = base - 64+ 16
710:  b9001fa0   str w0, [x29,#28]
714:  f9000ba1   str x1, [x29,#16]
int a = 100;
718:  52800c80   mov w0, #0x64                    // #100
71c:  b9002ba0   str w0, [x29,#40]        //a 入栈,保存到sp+16+40位置
int t = 10;
720:  52800140   mov w0, #0xa                    // #10
724:  b9002fa0   str w0, [x29,#44]        //t入栈保存

t += func(1,2,3,4,5,6,7,8,9,&a);
728:  52800120   mov w0, #0x9             //v9参数入栈       // #9
72c:  b90003e0   str w0, [sp]
730:  9100a3a0   add x0, x29, #0x28
734:  f90007e0   str x0, [sp,#8]         //p1参数入栈,此处仅存放a的地址&a
738:  52800020   mov w0, #0x1            //v1-v8参数直接使用w0-w7传入子程序 // #1
73c:  52800041   mov w1, #0x2                    // #2
740:  52800062   mov w2, #0x3                    // #3
744:  52800083   mov w3, #0x4                    // #4
748:  528000a4   mov w4, #0x5                    // #5
74c:  528000c5   mov w5, #0x6                    // #6
750:  528000e6   mov w6, #0x7                    // #7
754:  52800107   mov w7, #0x8                    // #8
758:  97ffffb4   bl  628 <func>
75c:  2a0003e1   mov w1, w0
760:  b9402fa0   ldr w0, [x29,#44]
764:  0b010000   add w0, w0, w1
768:  b9002fa0   str w0, [x29,#44]

return t;
76c:  b9402fa0   ldr w0, [x29,#44]       // 子程序返回值压栈作为返回值.
}
770:  d10043bf   sub sp, x29, #0x10
774:  a9417bfd   ldp x29, x30, [sp,#16]  // 恢复x29,x30,sp
778:  910103ff   add sp, sp, #0x40
77c:  d65f03c0   ret


。v0-v7直接使用x0-x7传递,其它参数使用压栈传递.

。局部变量也是压栈保存,需要使用的时再从栈中取出.

。子程序返回值存于x0(w0)中.

压栈图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: