历史上的今天
返回首页

历史上的今天

今天是:2025年01月30日(星期四)

2020年01月30日 | ARM函数调用过程分析

2020-01-30 来源:eefocus

1.ARM的栈帧

    先来看看ARM的栈帧布局图:

    上图描述的是ARM的栈帧布局方式,main stack frame为调用函数的栈帧,func1 stack frame为当前函数(被调用者)的栈帧,栈底在高地址,栈向下增长。图中FP就是栈基址,它指向函数的栈帧起始地址;SP则是函数的栈指针,它指向栈顶的位置。ARM压栈的顺序很是规矩,依次为当前函数指针PC、返回指针LR、栈指针SP、栈基址FP、传入参数个数及指针、本地变量和临时变量。如果函数准备调用另一个函数,跳转之前临时变量区先要保存另一个函数的参数。


    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连续空间内任意跳转。


  (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;

}



int main()

{

int i = 1, j = 2;

func(i, j, 3, 4);

return 0;

}


使用arm-linux-gcc编译后,使用ida打开:


.text:000083D0                 EXPORT main

.text:000083D0 main                                    ; DATA XREF: .text:000082C4o

.text:000083D0                                         ; .text:off_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


可以发现,在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恢复现场。


.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 =======================================


参考:

http://blog.chinaunix.net/uid-16459552-id-3364761.html

http://m.blog.csdn.net/blog/u011405813/41899197


推荐阅读

史海拾趣

BERGQUIST公司的发展小趣事

随着电子设备的不断发展和性能提升,热管理问题变得日益突出。BERGQUIST公司凭借其在热管理领域的深厚积累,成功研发出了一系列具有革命性的热管理产品。这些产品不仅有效解决了电子设备散热问题,还大大提高了设备的稳定性和可靠性。其中,BERGQUIST的柔性石墨散热片凭借其优异的导热性能和良好的适应性,在市场上获得了广泛认可。

Astron Wireless Technologies Inc公司的发展小趣事

随着公司的发展,Astron Wireless Technologies Inc开始寻求与其他行业的领军企业建立战略合作关系。通过与一家知名通信设备制造商的合作,公司成功将其无线通信技术集成到了对方的产品中,从而进一步扩大了市场份额。这一合作不仅提升了公司的知名度,还为公司带来了稳定的收入来源。

虹冠电子(Champion)公司的发展小趣事

虹冠电子注重全球市场的拓展,通过建立完善的营销网络和合作伙伴关系,将产品销往世界各地。公司在新竹、汐止以及美国硅谷等地设有研发中心和生产基地,能够为客户提供及时、高效的技术支持和服务。同时,虹冠电子还与国内优秀的晶圆封测大厂等合作伙伴建立了紧密的合作关系,共同推动电源管理技术的发展和应用。

Chauvin Arnoux公司的发展小趣事

进入上世纪三十年代,Chauvin Arnoux开始涉足摄影领域。1936年,公司成功开发了第一台摄影用曝光表,为摄影师提供了更为精确的曝光测量工具。这一产品的推出,不仅满足了摄影行业对精确测量的需求,也进一步扩大了Chauvin Arnoux在测量仪器领域的市场份额。

GWM Associates公司的发展小趣事
检查放大器器件的噪声系数是否超标,优化电路设计,加强电源滤波和地线处理。
Foxconn_Optical_Interconnect_Technologies__Inc.公司的发展小趣事
采用差分放大电路、共源共栅放大电路等结构,以提高增益和降低噪声。同时,注意电路的布局和布线,避免引入额外的噪声。

问答坊 | AI 解惑

现在把所有的活都交给手下干,不知道是好事还是坏事

现在coding不再做了,连架构都不做了,专职于做管理还有一些客户交流以及跟公司老总的交流问题,慢慢的,很多技术上的问题就疏远了,都在担心以后技术会不会慢慢就退化了!要跳槽如果没有manager该怎么办呢…

查看全部问答>

老电子工程师十年职场感悟

当电子工程师也是十余年了,不算有出息,环顾四周,也没有看见几个有出息的!回顾工程师生涯,感慨万千,愿意讲几句掏心窝子的话,也算给咱们师弟师妹们提个醒,希望他们比咱们强! [1]职业规划很重要,好好规划自己的路,不要跟着感觉走!根据 ...…

查看全部问答>

wince设备 MASS STORAGE问题

我们的设备上采用的是2G的NAND FLASH外加一个SD卡,三星提供的BSP和相关文档上说设备作为MASS STORAGE时,同时只能将其中一个作为MASS STORAGE连接到PC上,我们想连接PC的时候同时显示这两个存储空间,目前的候选方案是在应用程序上进行一些设置, ...…

查看全部问答>

Quartus II 有没有汉化版啊?

我是初次接触这个软件,英文版的有点看不懂,有没有高手能帮忙搞一个,将不胜感激!或者是只要兼容vista系统的版本都可以。急求!!!!!!!!!…

查看全部问答>

目目目上下班

1+1=?????…

查看全部问答>

流量计的参数远程控制

流量计的参数远程控制…

查看全部问答>

大虾帮帮忙啊,搞了好久了,还是不行...

本帖最后由 dontium 于 2015-1-23 13:26 编辑 正在做一个DSP--PCI的驱动,应用程序调试时出现如下: -----  damned.pjt - Debug  ----------------------------- [async_pci.cdb] \\"E:\\\\CCStudio_v3.1\\\\plugins\ ...…

查看全部问答>

程序问题

大家帮忙看下这个程序有些什么问题啊? 我想用这个程序测量占空比为百分之五十的方波 问什么液晶总是显示65535,而且frequency=1000000/period;这一句不管我把1000000换成多少他都显示的65535 不知道什么原因,请高手指点先谢了。   &nbs ...…

查看全部问答>

Hanker_M4学习笔记(一)

      可能看到我帖子的人,会有些失望,这么久了才提交个led循闪烁的程序,是不太应该,其实这几天都是在看M4的驱动编程,一直在归纳总结自己在M4学习中Keil软件方面的问题,大家也许看看我的文档,就能不这么责怪我了呵 ...…

查看全部问答>

MSP430开发注意事项与总结

以下是在使用MSP430中的一些总结: 1.系统时钟问题: 系统默认使用DCO,使用外部高速晶振XT2时必须自己开启XT2,并延时50us等待XT2起振,然后手工清除IFG1中的OFIFG位 !!!!一定要注意操作顺序:打开XT2->等待XT2稳定->切换系统时钟为XT2 若 ...…

查看全部问答>