这段时间在学习Uboot,看到start.S中有这么一句:
relocate:
adr r0,_start
ldr r2,_TEXT_BASE
... ...
事先把adr与ldr的伪命令用法粘上:
ADR:
ADR 可将一个立即值与 pc 值相加,并将结果写入目标寄存器。
语法
ADR{cond}{.W} Rd,label
其中:
cond 是一个可选的条件代码
.W 是可选的指令宽度说明符。
Rd 是要加载的寄存器。
label 是一个程序相对的表达式。label 必须在当前指令的一定范围之内。
用法
ADR 可生成与位置无关的代码,因为地址相对于程序或寄存器。
LDR (相对 pc)
加载寄存器。 地址为 pc 加偏移量。
语法
LDR{type}{cond}{.W} Rt, label
LDRD{cond} Rt, Rt2, label ; Doubleword
其中:
type 可以是下列项之一:
B 无符号字节(加载时零扩展为 32 位。)
SB 有符号字节(仅 LDR。 符号扩展为 32 位。)
H 无符号半字(加载时零扩展为 32 位。)
SH 有符号半字(仅 LDR。 符号扩展为 32 位。)
- 如果是字,则省略。
cond 是一个可选的条件代码 。
.W 是可选的指令宽度说明符。
Rt 是要加载或存储的寄存器。
Rt2 是第二个要加载或存储的寄存器。
label 是一个程序相对的表达式。
label 必须在当前指令的一定范围之内。
LDR 伪指令
使用以下项之一加载寄存器:
• 一个 32 位常数值
• 一个地址
语法
LDR{cond}{.W} Rt, =expr
LDR{cond}{.W} Rt, =label_expr
其中:
cond 是一个可选的条件代码
.W 是可选的指令宽度说明符。
Rt 是要加载的寄存器。
expr 取值为一个数值常数:
• 如果 expr 的值位于范围内,则汇编器将会生成一个 MOV 或 MVN 指令。
• 如果 expr 的值不在 MOV 或 MVN 指令的范围内,则汇编器会将常数放入文字池中,并会生成一个相对于程序的 LDR 指令,该 指令可从文字池中读取此常数。
label_expr 是地址的程序相对表达式或外部表达式,形式为加上或减去一个数值常数的标签。汇编器将label_expr 的值放入文字池中,并会生成一个相对于程序的 LDR 指令,该指令可从文字池中加载该值。
• 如果 label_expr 是一个外部表达式,或未包含在当前代码段内,则汇编器会在对象文件中放入一个链接器重新定位指令。 链接 器将在链接是生成该地址。
• 如果 label_expr 是一个局部标签,则汇编器会在对象文件中放入一个链接器重新定位指令,并会为该局部标签生成一个符号。该地址将在链接时生成。 如果局部标签引用了 Thumb 代码,则还会设置该地址的 Thumb 位(位 0)。
用法
LDR 伪指令的主要功能有:
• 当立即数由于超出了 MOV 和 MVN 指令的范围,而不能被移入寄存器中时,生成文字常数。
• 将相对于程序的地址或外部地址载入寄存器中。 无论链接器将包含 LDR 的ELF 代码段置于何处,该地址始终有效。
我是这么理解的:
_start是程序标号,_TEXT_BASE是在config.mk定义的变量,TEXT_BASE=0X33F80000,也就是说内存中或者存储设备中TEXT_BASE所对应地址的值为0X33F80000。那么第一句 adr r0,_start意味着,在该程序运行中,把程序标号_start所对应程序语句的运行地址(地址值,非地址中的内容)加载到r0寄存器中。第二句 ldr r2,_TEXT_BASE的意思是说,把变量TEXT_BASE对应地址中的数值(也就是0X33F80000)加载到r2寄存器中。
还有一点,为了实现同样的功能,我觉得第一句也能用ldr r0,=_start实现。
请大伙指正。
[ 此帖被pxwpsy在2010-10-22 15:45重新编辑 ]