从最简单的实例学习ARM 指令集(三)
上一篇讲到赋值运算,这篇讲讲子函数调用。先看最简单范例:test4.c
#include <stdio.h>
void f1()
{
}
void main()
{
int d = 4;
f1();
}
然后编译:arm-linux-gnueabihf-gcc test.c -o test4
然后看看汇编代码:
0000835c <f1>:
1 835c: b480 push {r7}
2 835e: af00 add r7, sp, #0
3 8360: 46bd mov sp, r7
4 8362: bc80 pop {r7}
直接跳到main函数里调用此函数时保存的LR值:
5 8364: 4770 bx lr
6 8366: bf00 nop
00008368 <main>:
程序用到了r7寄存器,所以须要保护以免破坏之前的数据,同一时候由于本函数调用子函数f1。须要用到lr寄存器保存返回值。故须要保存LR到栈里:
7 8368: b580 push {r7, lr}
8 836a: b082 sub sp, #8
9 836c: af00 add r7, sp, #0
10 836e: f04f 0304 mov.w r3, #4
11 8372: 607b str r3, [r7, #4]
跳转到函数f1的地址,同一时候把返回地址保存到LR寄存器:
12 8374: f7ff fff2 bl 835c <f1>
13 8378: f107 0708 add.w r7, r7, #8
14 837c: 46bd mov sp, r7
注意:此时不再使用bx lr返回了!
而是直接把第7行保存的LR值弹到PC寄存器上,下一条取地址指令就是取main函数的下一个地址。
事实上。採用原来的方式:pop {r7, lr} 以及 bx lr 返回也是能够的。仅仅只是会多使用一条指令:
15 837e: bd80 pop {r7, pc}
细心的人会发现。汇编代码8-11行与《从最简单的实例学习ARM 指令集(一)》中的范例test1.c一模一样。f1函数的机器指令十分简单,就是r7寄存器的压栈与出栈,相信大家都能看懂。
不知道大家有没有注意到,从main函数跳转到f1用的是bl指令,而从f1返回调用的是bx指令?
事实上这是由于涉及到arm处理器的两种工作状态:arm和thumb。子函数返回须要推断lr寄存器的[0]位来决定arm工作在那种状态,对子函数来说。偷懒的做法就是:无论主函数是什么。返回是虽然使用bx。让arm自己推断。而对main函数这样调用者来说。是知道当前处理器工作在thumb还是arm状态的,所以仅仅须要使用bl就能够了。
总结一下子函数的调用规则就是:bl用在函数内。bx用在返回。
下一篇讲讲函数调用过程中。參数是怎样传递的。
从最简单的实例学习ARM 指令集(三)的更多相关文章
- ARM指令集学习总结-转载
ARM指令集比较简单,本文介绍ARM指令集中需要注意和不易理解的地方. 一.ARM指令集是32位的,程序的启动都是从ARM指令集开始,包括所有异常中断都是自动转化为ARM状态,并且所有的指 ...
- ARM_Instruction_Set_Encoding_hacking(ARM指令集编码格式解读)
ARM指令集编码格式解读 说明: 1.本文参考的书籍<ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition>中的Cha ...
- 常用 ARM 指令集及汇编
ARM7TDMI(-S)指令集及汇编 ARM 处理器是基于精简指令集计算机(RISC)原理设计的,指令集和相关译码机制 较为简单,ARM7TDMI(-S)具有 32 位 ARM 指令集和 16 位 T ...
- ARM指令集相关知识
1.ARMv8引入了执行状态机制,分为AArch32和AArch64 AArch32为T32(Thumb)和A32(ARM). AArch64为A64一种指令集 A64和A32的指令都是32位宽,可以 ...
- 对arm指令集的疑惑,静态库运行,编译报错等问题
转载自http://www.jianshu.com/p/4a70aa03a4ea?utm_campaign=hugo&utm_medium=reader_share&utm_conte ...
- 实例学习SSIS(三)--使用包配置
原文:实例学习SSIS(三)--使用包配置 导读: 实例学习SSIS(一)--制作一个简单的ETL包 实例学习SSIS(二)--使用迭代 实例学习SSIS(三)--使用包配置 实例学习SSIS(四)- ...
- ARM指令集—SWP指令
ARM指令集-SWP指令 SWP和SWPB是ARM指令集中对存储单元的原子操作.即对存储单元的一次读和一次不可被切割. SWP和SWPB分别完毕存储器和寄存器之间 一个字(32bit)和一个字节(8b ...
- 【基于Android的ARM汇编语言系列】之五:ARM指令集与Thumb指令集
作者:郭嘉 邮箱:allenwells@163.com 博客:http://blog.csdn.net/allenwells github:https://github.com/AllenWell [ ...
- Thumb指令集与ARM指令集的差别
Thumb指令集 Thumb指令能够看做是ARM指令压缩形式的子集.是针对代码密度[1]的问题而提出的.它具有16为的代码密度.Thumb不是一个完整的体系结构,不能指望处理程序仅仅 ...
随机推荐
- BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊 (动态树LCT)
2002: [Hnoi2010]Bounce 弹飞绵羊 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 2843 Solved: 1519[Submi ...
- PyQt5 各种菜单实现
# -*- coding: utf-8 -*- # Created by PCITZDF on 2018/4/8 15:36. # FileName: menuandtools.py import s ...
- IDC门外汉-单线、双线、智能多线、BGP的区别
一.单线在此不多说,不是电信,就是网通机房,是,2005年前的机房情况: 二.双线:上般是从2004年到2008年用此方法较多,此今还有不少在用此法如下: 双线主机 有单IP和单网卡双IP地址,双网卡 ...
- mormot允许跨域访问
mormot允许跨域访问 ctxt.OutCustomHeaders:='Access-Control-Allow-Origin:*' 允许跨域访问 其实其他HTTP控件要实现跨域访问,也是类似设置. ...
- C#编程(七)----------命名空间
命名空间 命名空间的设计目的是为了提供一种让一组名称与其他名称分隔开的方式.在一个命名空间中声明的类的名称与另一个命名空间中声明的相同的类的名称不冲突. 关键字:namespace namespace ...
- Velocity中的ComparisonDateTool、MathTool、NumberT...
Velocity中的ComparisonDateTool.MathTool.NumberTool.SortTool.EscapeTool工具 可以从Apache官方网站自带的例子中查找,位置\velo ...
- DELIMITER关键词作用 替换结束符号
注意:“DELIMITER //”语句的作用是将MYSQL的结束符设置为//,因为MYSQL默认的语句结束符为分号;,为了避免与存储过程 中SQL语句结束符相冲突,需要使用DELIMITER 改变存储 ...
- Android之等比例显示图片
在android中,由于密度的影响,如果想得到图片的宽高是不行的,具体为什么我就大概说一下,具体的请搜索度娘或者古哥吧. 原因是如果你把图片放在drawable-mdpi里,而手机是属于drawabl ...
- Spark源码分析
名词解释 RDD全称为ResilientDistributedDataset,弹性分布式数据集.就是分布在集群节点上的数据集,这些集合可以用来进行各种操作.最重要的一点是,某个操作计算后的数据集可以缓 ...
- longest-substring-with-at-least-k-repeating-characters
https://leetcode.com/problems/longest-substring-with-at-least-k-repeating-characters/ public class S ...