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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/146877.html