找回密码
 注册
关于网站域名变更的通知
查看: 461|回复: 1
打印 上一主题 下一主题

ARM函数调用过程分析

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2021-4-12 13:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
1.ARM的栈帧
    先来看看ARM的栈帧布局图:
    上图描述的是ARM的栈帧布局方式,main stack frame为调用函数的栈帧,func1 stack frame为当前函数(被调用者)的栈帧,栈底在高地址,栈向下增长。图中FP就是栈基址,它指向函数的栈帧起始地址;SP则是函数的栈指针,它指向栈顶的位置。ARM压栈的顺序很是规矩,依次为当前函数指针PC、返回指针LR、栈指针SP、栈基址FP、传入参数个数及指针、本地变量和临时变量。如果函数准备调用另一个函数,跳转之前临时变量区先要保存另一个函数的参数。
( k' C3 I- t6 h3 [2 b
    ARM也可以用栈基址和栈指针明确标示栈帧的位置,栈指针SP一直移动,相比于x86,ARM更为鲜明的特点是,两个栈空间内的地址(SP+FP)前面,必然有两个代码地址(PC+LR)明确标示着调用函数位置内的某个地址。
2.ARM的汇编指令和栈操作
    ARM微处理器共有37个寄存器,其中31个为通用寄存器,6个为状态寄存器。但是这些寄存器不能被同时访问,具体哪些寄存器是可编程访问的,取决于微处理器的工作状态及具体的运行模式。但在任何时候,通用寄存器R0~R15、一个或两个状态寄存器都是可访问的。有三个特殊的通用寄存器:
    寄存器R13:在ARM指令中常用作堆栈指针SP
    寄存器R14:也称作子程序连接寄存器(Subroutine Link Register)即连接寄存器LR
    寄存器R15:也称作程序计数器PC
    ARM进行函数内压栈和出栈往往使用如下的语句:
  stmfd sp!, {r0-r9, lr}    ; 满递减入栈,给寄存器r0-r9,lr压栈,sp不断减4
  ldmfd sp!, {r0-r9, pc}    ; 满递减出栈,给寄存器r0-r9出栈,并使程序跳转回函数的调用点,sp不断增4
    常用的函数内外跳转指令有mov和BL,ARM有两种跳转方式:
  (1)mov pc,
    这种向程序计数器PC直接写跳转地址,能在4GB连续空间内任意跳转。
4 z- o% d/ c3 O* [7 O# Z. m9 u
  (2)通过 B BL BLX BX 可以完成在当前指令向前或者向后32MB的地址空间的跳转(为什么是32MB呢?寄存器是32位的,此时的值是24位有符号数,所以32MB?后面再查查看)。B是最简单的跳转指令。要注意的是,跳转指令的实际值不是绝对地址,而是相对地址——是相对当前PC值的一个偏移量,它的值由汇编器计算得出。BL很常用,它在跳转之前会在寄存器LR(R14)中保存PC的当前内容。BL的经典用法如下:
    bl NEXT       ; 跳转到NEXT
    ……
    NEXT
    ……
    mov pc, lr    ; 从子程序返回。
看代码:
int func(int a, int b, int c, int d)
{
       
        return 1;
}

) ~4 \, M; Q4 T( f9 K2 g/ @& m. O5 v% Z2 s* g$ ?
int main()
{
        int i = 1, j = 2;
        func(i, j, 3, 4);
        return 0;
}
5 O; u, f+ B1 [8 a1 r4 a
使用arm-linux-gcc编译后,使用ida打开:
$ v. C3 J7 O1 {, j
.text:000083D0                 EXPORT main
.text:000083D0 main                                    ; DATA XREF: .text:000082C4o
.text:000083D0                                         ; .textff_82DCo
.text:000083D0
.text:000083D0 b               = -0x14
.text:000083D0 a               = -0x10
.text:000083D0
.text:000083D0 IP = R12
.text:000083D0 FP = R11
.text:000083D0                 MOV     IP, SP
.text:000083D4                 STMFD   SP!, {FP,IP,LR,PC}
.text:000083D8                 SUB     FP, IP, #4
.text:000083DC                 SUB     SP, SP, #8
.text:000083E0                 MOV     R3, #1
.text:000083E4                 STR     R3, [FP,#a]
.text:000083E8                 MOV     R3, #2
.text:000083EC                 STR     R3, [FP,#b]
.text:000083F0                 LDR     R0, [FP,#a]
.text:000083F4                 LDR     R1, [FP,#b]
.text:000083F8                 MOV     R2, #3
.text:000083FC                 MOV     R3, #4
.text:00008400                 BL      func
.text:00008404                 MOV     R3, #0
.text:00008408                 MOV     R0, R3
.text:0000840C                 SUB     SP, FP, #0xC
.text:00008410                 LDMFD   SP, {FP,SP,PC}
.text:00008410 ; End of function main

% J# j* ?6 u3 u! V3 G! ]0 o1 x
可以发现,在main函数中,使用IP(R12)暂时保存栈指针sp,然后使用堆栈操作指令stmfd将栈帧(FP)、IP、程序返回地址(LR)、程序计数器(PC)压栈,以保护现场,然后使用sub fp,ip,#4使fp指向当前函数栈帧的栈底,sub sp,sp,#8,为当前函数局部变量分配看空间。接下来通过寄存器传递参数r1,r2,r3,r4。使用BL指令调用函数,BL指令同时也会将当前指令的下一条指令地址赋给LR,以跳转回来。最后使用ldmfd恢复现场。

; V5 x2 M2 I4 X
.text:000083A0 ; =============== S U B R O U T I N E =======================================
.text:000083A0
.text:000083A0 ; Attributes: bp-based frame
.text:000083A0
.text:000083A0                 EXPORT func
.text:000083A0 func                                    ; CODE XREF: main+30p
.text:000083A0
.text:000083A0 var_1C          = -0x1C
.text:000083A0 var_18          = -0x18
.text:000083A0 var_14          = -0x14
.text:000083A0 var_10          = -0x10
.text:000083A0
.text:000083A0                 MOV     R12, SP
.text:000083A4                 STMFD   SP!, {R11,R12,LR,PC}
.text:000083A8                 SUB     R11, R12, #4
.text:000083AC                 SUB     SP, SP, #0x10
.text:000083B0                 STR     R0, [R11,#var_10]
.text:000083B4                 STR     R1, [R11,#var_14]
.text:000083B8                 STR     R2, [R11,#var_18]
.text:000083BC                 STR     R3, [R11,#var_1C]
.text:000083C0                 MOV     R3, #1
.text:000083C4                 MOV     R0, R3
.text:000083C8                 SUB     SP, R11, #0xC
.text:000083CC                 LDMFD   SP, {R11,SP,PC}
.text:000083CC ; End of function func
.text:000083CC
.text:000083D0
.text:000083D0 ; =============== S U B R O U T I N E =======================================

2 }  P' V% c  n1 R% e2 D: O  w1 G, [
  • TA的每日心情
    开心
    2023-1-3 15:10
  • 签到天数: 2 天

    [LV.1]初来乍到

    2#
    发表于 2021-4-12 15:25 | 只看该作者
    ARM微处理器共有37个寄存器,其中31个为通用寄存器,6个为状态寄存器
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-6-24 07:05 , Processed in 0.078125 second(s), 23 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表