ADR的定义为:小范围的地址读取伪指令,ADR指令将基于PC相对偏移的地址值读取到寄存器中,在编译源程序时ADR伪指令被编译器 替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,刚产生错误。
在如上的定义中,有两个关键信息:⑴将基于PC相对偏移的地址值读取到寄存器中;⑵被编译器替换成一条合适的指令。ADR指令只能将地址值读取到寄存器中,而不能是其它的立即数,并用只能用一条指令。
如果在汇编程序中使用ADR R1,ResetHandel语句,其中ResetHandel是汇编程序中的一个标签,此条伪指令的作用是把ResetHandel标签所在的指令地址 读取到寄存器R0中。当汇编器对此条伪指令进行编译的时候,将会编译成机器码:0xE28F100C,转换成二进制就是1110 0010 1000 1111 0001 0000 0000 1100,下面对这个机器码进行分析:
根据上面的分析,可以看到,编译器在编译的时候把ADR伪指令编译成一个ADD R1,PC,Immediate指令,其中Immediate是一个立即数,数值是ResetHandel语句和此条伪指令之间的差值,由编译器自动算 出。由于立即数寻址的约束,这个Immediate存在一定的约束,所以会出现定义中所说的不能用一条指令实现。
LDR说的定义为:大范围地址读取伪指令,LDR伪指令用于加载32们的立即数或一个地址值到指定寄存器。在汇编编译源程序时,LDR伪指令被编译 器替换成一条合适的指令。若加载的常数未超出MOV或者MVN的范围,刚使用MOV或MVN指令代替该LDR伪指令,否则汇编器将常量放入字池,并使用一 条程序相对偏移的LDR指令从文字池读出常量。
与ARM指令的LDR相比,伪指令的LDR的参数有"="号。
在如上的定义中,有三个关键信息:⑴用于加载32们的立即数或一个地址值到指定寄存器;⑵被编译器替换成一条合适的指令;⑶优先使用MOV或MVN指令代替该指令。
如果使用MOV指令,那就使用立即数寻址的方式,但是立即数寻址存在一个范围白约束,所以不是所以的常数都可以使用立即数寻址白方式。当不能使用立 即数寻址方式时,就把常量放入文字池,使用一条程序相对于PC寻址的LDR指令把文字池的内容读取到寄存器中。立即数和地址值的操作方式是一样的。
如果有伪指令:LDR R0,=0x。那编译器在编译该伪指令的时候将会编译成机器码:1110 0101 1001 1111 0000 0000 0001 0100,下面对这个机器码进行分析:
由上面分析可知,伪指令LDR R0,=0x其实就是被编译成LDR R0,[PC,Immediate]。其中立即数0x被储存在一个文字池中,他的地址和指令LDR R0,[PC,Immediate]的地址之前差了Immediate。因此指令LDR R0,[PC,Immediate]就可以把立即数0x读取到R0中了。
原文:http://tanglei9098.blog.163.com/blog/static/01/
LDR 是ARM中的指令,也是伪指令。
当用 LDR r, =imd // r 为寄存器, imd为立即数
LDR 是一条伪指令。编译器会根据 立即数的大小,决定用 ldr 指令或者是mov或mvn指令。
当imd能用mov或者mvn操作时,就将它翻译成一条mov或mvn指令。当imd大于mov或mvn能够操作的数时,编译器会将imd存在一个内存单元中,然后再用一条ldr指令加载这个内存单元的的值到寄存器中。
LDR r, label 和 LDR r, =label的区别:
LDR r, =label 会把label表示的值加载到寄存器中,而LDR r, label会把label当做地址,把label指向的地址中的值加载到寄存器中。
譬如 label的值是 0x8000, LDR r, =label会将 0x8000加载到寄存器中,而LDR r, label则会将内存0x8000处的值加载到寄存器中。
ADR 和 ADRL 伪指令:
ADR 和 ADRL 伪指令用于将一个地址加载到寄存器中。
ADR为小范围的地址读取伪指令。ADR指令将基于PC相对偏移的地址值读取到寄存器中。在汇编编译源程序时,ADR伪指令被编译器替换在一条合适 的指令,通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能使用一条指令实现,则产生错误。其能加载的地址范围,当为字节对齐 时,是-1020~1020,当为非字对齐时在-255~255之间。
ADRL是中等范围的地址读取指令。会被编译器翻译成两条指令。如果不能用两条指令表示,则产生错误。
ADRL能加载的地址范围当为非字节对齐时是-64K~64K之间;当为字节对齐时是-256K~256K之间。
推荐阅读最新更新时间:2024-11-02 10:47
我们可以把可执行文件分为2种情况:存放态和运行态
1.存放态:可执行文件经过烧到存储介质上(flash或磁盘)的分布,此时可执行文件通常有2部分组成,代码段和数据段,代码段又分为可执行代码段 (.text)和只读数据段(.rodata),数据段可以分为初始化数据段(.data)和未初始化代码段(.bss),如下:
+-------------+-----------
| .bss | (ZI)
+-------------+-- 数据段
| .data | (RW)
+-------------+-----------
| .rodata |
|_____________| 代码段(RO)
| .text |
+-------------+-----------
.text代码段,.rodata只读数据段,.bss是未初始化全局变量段, .data是初始化被赋值的全局变量
2.运行态:可执行文件经过装载后就变成为运行态,
当可执行文件装载后, 在RAM中的分布如下:
| ... |
+-------------+-- ZI段结束地址
| ZI 段 |
+-------------+-- ZI段起始地址
| 保留区2 |
+-------------+-- RW段结束地址
| RW 段 |
+-------------+-- RW段起始地址
| 保留区1 |
+-------------+-- RO段结束地址
| RO 段 |
+-------------+-- RO段起始地址
ZI段主要是未初始化数据,RW主要是自动变量,RO主要是代码段。
elf文件
elf文件是UNIX系统实验室开发的,主要包括可执行文件,可充分定位文件与可共享库文件等。按功能分又可分为链接文件和可执行文件。一个elf文件可以使用binutils工具集里面的readelf来查看,比如readelf -h u-boot查看u-boot文件头。
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: ARM
Version: 0x1
Entry point address: 0x0
Start of program headers: 52 (bytes into file)
Start of section headers: (bytes into file)
Flags: 0x, Version5 EABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 4
Size of section headers: 40 (bytes)
Number of section headers: 25
Section header string table index: 22
概述
binutils是一组二进制工具集,它包括addr2line、ar、gprof、nm、objcopy、objdumpr、ranlib、size、strings、strip等。
ar软件
ar用于建立、修改、提取库文件。ar至少需要两个参数才能运行,比如:
$ ar rv libtest.a add.o minus.o
是指将add.o、minus.o做成库文件libtest.a。其中r是指将文件列表插入归档文件,v是指得到操作版本号。
这样我们引用库文件的时候就可以使用:
$ gcc -o test test.c -ltest
nm软件
nm软件的作用是现实目标文件的信息和属性,比如:
$ nm test.o
U Add
00000000 T main
U Minus
U printf
这里U标志符号未被定义,T表示符号位于代码段,D表示符号位于已初始化数据部分,还有B、t、r、b、R、A、W、d等等。
objcopy软件
objcopy软件用来将某种格式的目标软件转换成另一种格式的目标软件。
比如u-boot使用本软件将u-boot转换成u-boot.srec格式。
objdump软件
本软件可以用来进行反汇编和查看目标文件信息。
ld软件
ld软件用来吧各种目标文件和库文件链接在一起,定位数据和函数的地址,最终生成可执行文件。
链接描述文件介绍:
链接描述文件用于显式的控制ld的链接过程。ld的“-T”选项可以指定链接描述文件的名称。
链接描述文件遵循特定的链接命令语言——linker scripts的语法。比如u-boot.lds
参考文献:
《韦东山——嵌入式Linux应用开发完全手册》第15章
uboot之start.s分析
DENX的u-boot是一个狠庞大的系统,研究透彻u-boot的Make的运作同样是一个狠庞大的工程,目前我仅参考以上两个参考文档对S3C2440的u-boot的编译的Make相关的文件和命令做一个简单说明。如果深入学习《嵌入式Linux应用开发完全手册》是一个很好的指引。
一般针对S3C2440的移植都是参照smdk2410来的,所以在smdk2410的目录,拷贝一个做为smdk2440;
另外,编译后,可以直接查找*.o文件查看已编译选项;
读Makefile可以发现u-boot.lds的用途。
start.S是整个uboot的起始文件。
以上四项《嵌入式Linux应用开发完全手册》已经从源头说明了其组成原理。
一 make smdk2440_config的解析:
一般的,在配置u-boot的时候,我们会输入:
make smdk2440_config
从早期的u-boot版本中可以见到这样的几行:
MKCONFIG=$(SRCTREE)/mkconfig
......
smdk2410_config : unconfig
@$(MKCONFIG) smdk2410 arm arm920t smdk2410 NULL s3c24x0
由此翻译过来,make smdk2440_config就相当于:
https://news.eeworld.com.cn/mcu/mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0
二 对于https://news.eeworld.com.cn/mcu/mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0的解析:
这个mkconfig是一个shell脚本,它根据传入的参数,做了如下工作:
ln -s asm-$2 asm
ln -s arm-$6 asm-$2/arch
ln -s proc-armv arm-$2/proc
创建config.mk文件
ARCH = arm
CPU = arm920t
BOARD = smdk2410
SOC = s3c24x0
创建于开发板相关的config.h文件
#include
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/rfx/19946.html