AAPCS 学习课后练习 - 通过一个小例子来讲解
2015-12-13 15:57
561 查看
一、有个函数有10个参数,请问是参数是如何传递的?请画出压栈图(32位 / 64位).
<1> 首先看ARM32
。编写 test.c
。编写Android.mk
。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
。v1-v4使用r0-r3直接传入子程序
。v5-p1使用压栈方式传入,子程序结果返回值存于r0
。局部变量压栈保存,需要使用时候再从栈弹出
压栈图
![](http://note.youdao.com/yws/public/resource/a9c45d557c95072b2ad868a9b2f873b4/C2D168A58148413CA311B076A6010844)
![](http://note.youdao.com/yws/public/resource/a9c45d557c95072b2ad868a9b2f873b4/C2866F6C95B0464DB4110F42A973C4E0)
![](http://note.youdao.com/yws/public/resource/a9c45d557c95072b2ad868a9b2f873b4/E4D0CCE1857940C495D1D4369DF6753B)
<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)
。v0-v7直接使用x0-x7传递,其它参数使用压栈传递.
。局部变量也是压栈保存,需要使用的时再从栈中取出.
。子程序返回值存于x0(w0)中.
压栈图:
<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)中.
压栈图:
相关文章推荐
- 连续特征离散化和归一化
- Github博客地址
- Linux 防火墙配置
- [Coursera]算法基础_Week4_动态规划(1)_Q1
- Python3切换华为hi link设备数据开关
- DVWA系列之11 Brute Force中的密码绕过
- DVWA系列之11 Brute Force中的密码绕过
- Poj3984- dfs -迷宫问题
- MTK校准默认参数修改(2010-3-29 16:16)
- 数据结构问题集锦 - Max Points on a Line问题
- 流程
- Redhat7 配置ipv6
- 分享Python字符串关键点
- [Coursera]算法基础_Week3_递归_Q2
- web工程复制后改名字后遇到问题,怎么解决
- python 多线程学习
- 倍数提高工作效率的 Android Studio 奇技
- iOS Block传值
- 【openjudge】仙岛求药
- 使用SDWebImage时的内存管理问题