uboot的start.s文件作用很简单。就初始化和启动芯片等功能。
在写start.S的时候,一定注意这个文件在uboot中是一个相对运行的文件,与文件所处的地址无关。而其他的文件都是地址相关的,只能在ram里面运行。(ram或者rom中要修改TEXT_BASE 但环境变量不能在flash中更改,所以还是只能运行在ram)
要判断是否该段程序是否地址无关,最好把语句翻成最原始最原始的语句,这种语句接近于机器码(参考arm嵌入式基础教程 周立功)。
在汇编中的地址包含两个概念:
一个是局部的标号label (在编译时被计算)
另外一种是全局的符号symbol(在链接时计算出来,是绝对地址,具体的值要通过开发者自己设置)
要很注意:
理解汇编的标号的意思:
1:在汇编中,标号存在于某个语句中,只与某个语句挂钩,标号的作用要翻成原始的汇编码去看。
例如:
ldr,label表示的是 ldr,【pc,#a】 a是在汇编过程中计算出来的具体的值。而后面这句话是arm的执行语句,无论程序在哪运行,都会运行 ldr,【pc,#a】。所以pc值不一样,运行的过程也不一样(这个是取某个地址上的内容,结果是一样的)
而label这样的标号为局部的标号。
最重要的是:
adr r x,label 表示的是add ,pc,#a 。这里的pc都是当前值。a是局部标号,是在汇编的过程中计算出来的。
所以当程序运行所在的地址不相同时,rx的值也不一样。这就uboot为什么要使用adr来观察是否是在flash中运行的道理。
汇编还有很多要注意的地方:
因为一个机器码为32位,除了一些参数,命令外留给立即数的不多。除了伪指令ldr能够获得立即数外,其他的指令中所含的立即数都是受到位数的限制的。要把arm汇编的指令分成几类来看。
像ldr,str属于存储读取指令,操作的是内存,flash
像add,mov等是寄存器操作指令
这些指令后都有少部分留给立即数的。所以可以使用标号,而标号不是表示的各别值,而需要汇编器去计算以符合32机器码的要求。
我的atmel arm7还有一个remap的功能。
remap之后,因为流水线的缘故,所以mov pc,r12会执行。
在atmel公司给的启动程序中一般会 1:ldr r12,initremap。。
2:remap操作。。
3: mov pc,r12
4:initremap:
5: dcd (.word)aaa
6:aaa:。。。。。。
在uboot的代码中也有上面红色部分表示的代码。这里的aaa就不再是局部标号了,而是一个绝对地址,一个具体的数,是全局标号,通过设置ro,ri或者通过uboot的u-boot。lds文件设置(一般不用设置,就是0x0+TEXT_BASE)后,链接器会算出来。 所以如果单单只是在flash中运行,设置ro的值,这个值就被固定了。在uboot中start。s要求是位置无关的,所以remap之后,必须保留当前的PC值, 清楚该pc值与remap后pc值的差值。利用上面一样的方式跳到原来的flash中运行。
说道这个,这个说下_start。在start.s中,所有用到start。s的执行语句都是将_start作为局部标号。
如adr r0,_start(机器码 如上面所述)
而。gloabl _start
_arm_boot:
.word _start中start是全局标号,是链接器算出来的绝对地址。
|