看下面这个ARM汇编吧 BL NEXT ;跳转到子程序 ......... ;NEXT处执行 NEXT .......... MOV PC,LR ;从子程序返回 这里的BL是跳转的意思,LR(R14)保存了返回地址 PC(R15)是当前地址,把LR给PC就是从子程序返回 这里有一下总结 首先 1.SP(R13) LR(R14)PC(R15)
2.lr(r14)的作用问题,这个lr一般来说有两个作用: 3.》我以前看书不懂的地方 子程序返回的三种方法 现在总结如下 1.MOV PC,LR 2.BL LR 3.在子程序入口处使用以下指令将R14存入堆栈 STMFD SP!,{<Regs>,LR} 对应的,使用以下指令可以完成子程序的返回 LDMFD SP!, {<Regs>,LR}
转载自:http://blog.csdn.net/xgx198831/article/details/8333446
汇编学习总结记录
1.1. 汇编学习总结记录
比如,C语言中定义一个标号ERR_NODEV:
汇编中的标号 = C语言中的标号Label 1.1.2. 汇编中的跳转指令=C中的goto 对应地,和上面的例子中的C语言中的编号和掉转到标号的goto类似,汇编中,对于定义了标号,那么也会有对应的指令,去跳转到对应的汇编中的标号。 这些跳转的指令,就是b指令,b是branch的缩写。 b指令的格式是: b{cond} label 简单说就是跳转到label处。 用和上面的例子相关的代码来举例:
【总结】 汇编中的b跳转指令 = C语言中的goto 1.1.3. 汇编中的.globl=C语言中的extern 对于上面例子中: .globl _start 中的.global,就是声明_start为全局变量/标号,可以供其他源文件所访问。 即汇编器,在编译此汇编代码的时候,会将此变量记下来,知道其是个全局变量,遇到其他文件是用到此变量的的时候,知道是访问这个全局变量的。 因此,从功能上来说,就相当于C语言用extern去生命一个变量,以实现本文件外部访问此变量。 【总结】 汇编中的.globl或.global = C语言中的extern 1.1.4. 汇编中用bl指令和mov pc,lr来实现子函数调用和返回 和b指令类似的,另外还有一个bl指令,语法是: BL{cond} label 其作用是,除了b指令跳转到label之外,在跳转之前,先把下一条指令地址存到lr寄存器中,以方便跳转到那边执行完毕后,将lr再赋值给pc,以实现函数返回,继续执行下面的指令的效果。 用下面这个start.S中的例子来说明:
然后在cpu_init_crit部分,执行完毕后,最后调用 mov pc, lr,将lr中的值,赋给pc,即实现函数的返回原先 bl cpu_init_crit下面那条代码,继续执行函数。 上面的整个过程,用C语言表示的话,就相当于
而关于C语言中,函数的跳转前后所要做的事情,都是C语言编译器帮我们实现好了,会将此C语言中的函数调用,转化为对应的汇编代码的。 其中,此处所说的,函数掉转前后所要做的事情,就是: 函数跳转前:要将当前指令的下一条指令的地址,保存到lr寄存器中。 函数调用完毕后:将之前保存的lr的值给pc,实现函数跳转回来。继续执行下一条指令。 而如果你本身自己写汇编语言的话,那么这些函数跳转前后要做的事情,都是你程序员自己要关心,要实现的事情。 【总结】 汇编中bl + mov pc,lr = C语言中的子函数调用和返回 1.1.5. 汇编中的对应位置有存储值的标号 = C语言中的指针变量 像前文所解析的代码中类似于这样的:
而该标号中对应的位置,所存放的是一个word的值,具体的数值是TEXT_BASE,此处的TEXT_BASE是在别处定义的一个宏,值是0x33D00000。 所以,即为: 有一个标号_TEXT_BASE,其对应的位置中,所存放的是一个word的值,值为TEXT_BASE=0x33D00000。 总的来说,此种用法的含义,如果用C语言来表示,其实更加容易理解: int *_TEXT_BASE = TEXT_BASE = 0x33D00000 即: int *_TEXT_BASE = 0x33D00000 【C语言中如何引用汇编中的标号】 不过,对于这样的类似于C语言中的指针的汇编中的标号,在C语言中调用到的话,却是这样引用的:
其中,对应的汇编中的代码为:
【总结】 汇编中类似这样的代码: label1: .word value2 就相当于C语言中的: int *label1 = value2 但是在C语言中引用该标号/变量的时候,却是直接拿来用的,就像这样: label1 = other_value 其中label1就是个int型的变量。 1.1.6. 汇编中的ldr+标号,来实现C中的函数调用 接着上面的内容,继续解释,对于汇编中这样的代码: 第一种: ldr pc, 标号1 。。。 标号1:.word 标号2 。。。 标号2: 。。。(具体要执行的代码) 或者是, 第二种: ldr pc, 标号1 。。。 标号1:.word XXX(C语言中某个函数的函数名) 的意思就是,将地址为标号1中内容载入到pc中。 而地址为标号1中的内容,就是标号2。 所以上面第一种的意思: 就很容易看出来,就是把标号2这个地址值,给pc,即实现了跳转到标号2的位置执行代码,就相当于调用一个函数,该函数名为标号2. 第二种的意思,和上面类似,是将C语言中某个函数的函数名,即某个地址值,给pc,实现调用C中对应的那个函数。 两种做法,其含义用C语言表达,其实很简单: PC = *(标号1) = 标号2 举个例子就是: 第一种:
就是实现了将标号1,_software_interrupt,对应的位置中的值,标号2,software_interrupt,给pc,即实现了将pc掉转到software_interrupt的位置,即实现了调用函数software_interrupt的效果。 第二种:
其中,start_armboot是C语言文件中某个C语言的函数。 【总结】 汇编中,实现函数调用的效果,有如下两种方法: 方法1: ldr pc, 标号1 。。。 标号1:.word 标号2 。。。 标号2: 。。。(具体要执行的代码) 方法2: ldr pc, 标号1 。。。 标号1:.word XXX(C语言中某个函数的函数名) 1.1.7. 汇编中设置某个寄存器的值或给某个地址赋值 在汇编代码start.S中,看到不止一处, 类似于这样的代码: 形式1:
形式2:
其中,形式1是直接通过mov指令来将0这个值赋给r1寄存器,和形式2中的通过ldr伪指令来将0x3ff赋给r1寄存器,两者区别是,前者是因为已经确定所要赋的值0x0是mov的有效操作数,而后者对于0x3ff不确定是否是mov的有效操作数 (如果不是,则该指令无效,编译的时候,也无法通过编译,会出现类似于这样的错误:
所以才用ldr伪指令,让编译器来帮你自动判断: (1)如果该操作数是mov的有效操作数,那么ldr伪指令就会被翻译成对应的mov指令。 举例说明: 汇编代码:
举例说明: 汇编代码:
【总结】 汇编中,一个常用的,用来给某个地址赋值的方法,类似如下形式:
转载自:http://bbs./thread-2312780-1-1.html |
|
来自: cuibaofeng > 《ARM汇编》