转 -- ARM 中 LDR伪指令
我们知道ARM CPU中有一条被广泛使用的指令LDR,它主要是用来从存储器(确切地说是地址空间)中装载数据到通用寄存器。但不论是ARMASM还是GNU ARM AS,都提供了一条与之同名的伪指令LDR,而在实际中使用该伪指令的情况也较多,那他们有什么不同呢?下面我谈谈我的理解。
由于我使用GNU工具链,所以以下的内容都以GNU AS的ARM语法为准。
LDR伪指令的语法形式如下:
LDR <reg>, = <constant-expression>
这个常量表达式<constant-expression>中可以包含Label(在ARM汇编中Label会在连接时解释为一个常数),且其中的常数前不加#符号。
.equ STACK_BASE, 0x0c002000
.equ STACK_SIZE, 0x00001000 .text
ldr sp, = STACK_BASE
ldr sl, = STACK_BASE - STACK_SIZE
ldr pc, = entry
这是一个合法的汇编文件,它把堆栈基址设为0x0c002000,栈限设为0x0c001000,然后跳到entry所标识的C程序中执行。
下面我们假设符号“entry”的地址为0x0c000000。
我们如果把上面代码写成:
.text
mov sp, #0x0c002000
mov sl, #0x0c001000
mov pc, #0x0c000000
汇编器会报错:
demo.s: Assembler messages:
demo.s:2: Error: invalid constant -- `mov sp,#0x0c002000'
demo.s:3: Error: invalid constant -- `mov sl,#0x0c001000'
说起这个错误的原因可就话长了,简而言之是因为RISC有一个重要的概念就是所有指令等长。在ARM指令集中,所有指令长度为4字节(Thumb指令是2
字节)。那问题就来了,4字节是不可能同时存的下指令控制码和32位立即数的,那么我要把一个32位立即数(比如一个32位地址值)传送给寄存器该怎么
办?
RISC CPU提供一个通用的方法就是把地址值作为数据而不是代码,从存储器中相应的位置读入到寄存器中,待会我们会看到这样的例子。
此外ARM还提供另一种方案。由于传送类指令的指令控制码部分(cond, opcode, S, Rd, Rn域)占去了20个字节,那能提供给立即数的就只剩12个位了。
ARM并未使用这12个位来直接存一个12位立即数,而是使用了类似有效数字一样的概念,只存8个字节的有效位和一个4位的位偏移量(偏移单位为2)。这个东西在ARM被叫做术语immed_8,有兴趣的人可以找资料了解一下,到处都有介绍。
可以看出ARM的这个方法能直接使用的立即数是相当有限的,像0xfffffff0这样的数显然无法支持。别着急,ARM的传送类指令中还有一个MVN指
令可以解决该问题。显然0x0000000f是一个有效立即数,MVN会先将其取反再传送,这样有效立即数的范围又扩充了一倍。
可就算如此仍有大量的32位立即数是无效的,比如上面那个例子中的0x0c002000和0x0c001000。面对这种问题一是使用RISC的通用方法,二是分次载入。
比如可以这样载入0x0c002000:
.text
mov sp, #0x0c000000
add sp, sp, #0x00002000
或者:
.text
mov sp, #0x0c000000
orr sp, sp, #0x00002000
感觉很狡猾是吧,呵呵。但是要注意它和方法一的一大区别:需要多条指令。那么在一些对指令数目有限制的场合就无法使用它,比如异常向量表处要做长跳转(超过±32MB)的话就只能用方法一;还有就是在同步事务中该操作不是原子的,因此可能需要加锁。
扯了这么多再回到LDR伪指令上来。显然上面的内容是复杂繁琐的,如果然程序员在写程序的时候还要考虑某个数是不是immed_8一定超级麻烦,因此为了减轻程序员的负担才引入了LDR伪指令。
你一定很好奇第一段代码demo.s被GNU AS变成了什么,好,让我们在Linux环境下执行下面的命令:
arm-elf-as -o demo.o demo.s
arm-elf-objdump -D demo.o
结果:
demo.o: file format elf32-littlearm Disassembly of section .text: <.text>:
: e59fd004 ldr sp, [pc, #] ; c <.text+0xc>
: e59fa004 ldr sl, [pc, #] ; <.text+0x10>
: e59ff004 ldr pc, [pc, #] ; <.text+0x14>
c: 0c002000 stceq , cr2, [r0]
: 0c001000 stceq , cr1, [r0]
: andeq r0, r0, r0
Disassembly of section .data:
由于entry还没连上目标地址,objdump反汇编会认为是0,我们先不管它。另外两条LDR伪指令变成了实际的LDR指令!但目标很奇怪,都是[pc, #4]。那好我们看看[pc, #4]是什么。
我们知道pc中存放的是当前指令的下下条指令的位置,也就是. + 8。那么上面的第一条指令ldr sp, [pc, #]中的pc就是0x8,pc + 4就是0xc,而[0xc]的内容正是0x0c002000;同理,第二条ldr指令也是如此。显然这里LDR伪指令采用的是RISC通用的方法。
另外要说的是,如果LDR的是一个immed_8或者immed_8的反码数,则会直接被解释成mov或mvn指令。如ldr pc, = 0x0c000000会被解释成mov pc, 0x0c000000。
最后一点补充,我发现arm-elf-gcc通常都用累加法。如C语句中的i = 0x100ffc04;会变成类似于以下的语句:
mov r0, #0x10000004
add r0, r0, #0x000ff000
add r0, r0, #0x00000c00
...
原因不详。
转载地址:http://blog.csdn.net/axx1611/article/details/2335410/
转 -- ARM 中 LDR伪指令的更多相关文章
- ARM中LDR伪指令与LDR加载指令
ARM指令集中,LDR通常都是作加载指令的,但是它也可以作伪指令. LDR伪指令的形式是“LDR Rn,=expr”.下面举一个例子来说明它的用法. COUNT EQU 0x4000310 ...
- ARM汇编中ldr伪指令和ldr指令(转载)
转自:http://blog.csdn.net/ce123_zhouwei/article/details/7182756 ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成, ...
- ARM LDR伪指令使用方法具体解释
LDR伪指令 10.45 LDR pseudo-instruction 功能:把一个32位马上数或一个32位的内存地址载入到一个寄存器中. 注意:这里描写叙述的是LDR伪指令,而不是LDR指令 ...
- ARM学习笔记9——ARM汇编汇编语言中的伪指令
ARN汇编器支持ARM伪指令,这些伪指令在汇编阶段被翻译成ARM或Thumb指令.ARM伪指令包含ADR.ADRL.MOV32和LDR.一.ADR伪指令 1.作用 ADR是小范围地址读取伪指令,基于P ...
- ARM汇编程序中的伪指令
转自http://blog.chinaunix.net/uid-13701930-id-336459.html 4.1 ARM汇编器所支持的伪指令 在ARM汇编语言程序里,有一些特殊指令助记符,这些助 ...
- arm中的ldr指令
label .equ 0x53000000 ldr r0, label : 将0x53000000地址处的值放入r0中 ldr r0, =label : 将0x53000000付值给r0.
- ARM中的汇编指令
Arm指令,32位的指令集,一共有16条的基本指令,每条指令都可以按条件执行, 指令都是32bit的,高四位是条件码[31:28], Thumb指令,16位的指令集,执行效率比arm指令集要低,但是节 ...
- [zhuan]arm中的汇编指令
http://blog.csdn.net/qqliyunpeng/article/details/45116615 一. 带点的(一般都是ARM GNU伪汇编指令) 1. ".text& ...
- ARM中的---汇编指令
一. 带点的(一般都是ARM GNU伪汇编指令) 1. ".text".".data".".bss" 依次表示的是"以下是代码段& ...
随机推荐
- 字符串经过base64编码后的长度与原字符串的长度是什么关系呀?
beforeEncode为Encode之前的字符串 那么Encode后的字符串长度为: 1.如果beforeEncode.length()是3的整数倍,那么长度为 (beforeEncode.len ...
- vue组件讲解(is属性的用法)
什么是组件? 在说之前我们先搞清楚什么是组件?这样对我们下边的学习是很有帮助的. 组件(Component)是Vue.js最强大的功能之一.组件可以扩展HTML元素,封装可以重复使用的代码.在较高层次 ...
- vSphere Client 连接ESXi 或者是vCenter 时虚拟机提示VMRC异常的解决办法
1. 自己的vSphere 连接vCenter 向管理虚拟机 结果发现总是有异常. 提示如图示 VMRC控制台的连接已经断开 2. 花了比较长的时间也没搞定. 后来百度发现 关闭一个进程 然后重新登录 ...
- DB磁盘满导致Zabbix Server Crash一例
故障描述 今天线上zabbix出现几次数据中断的情况,经排查为DB服务器磁盘空间不足导致的.还好我们目前我们zabbix,falcon两套监控系统并存,哈哈. 故障排查过程没什么技术含量,简单的将故障 ...
- Visual Categorization with Bags of Keypoints
1.Introduction and backgrounds 作为本周的论文之一,这是一篇bag of features的基本文章之一,主要了解其中的基本思路,以及用到的基本技术,尽量使得细节更加清楚 ...
- 为什么家里的宽带的IP显示的是外地?
作者:NightCoffee链接:https://www.zhihu.com/question/22547945/answer/21734955来源:知乎著作权归作者所有.商业转载请联系作者获得授权, ...
- shiro异常类型
<!-- 身份认证异常 --> <!-- 身份令牌异常,不支持的身份令牌 --> org.apache.shiro.authc.pam.UnsupportedTokenExce ...
- Oracle 修改dmp的表空间
1.百度下载 UltraEdit 并安装 2.打开程序,文件-->打开-->找到dmp 文件太大会提示,选择第一个默认,确定 3.按CTRL+H 转成十六进制编辑 4.例如:dmp里面 ...
- DPHARD
此篇收集各类DP题. <1D1D动态规划优化初步>的3个模型 1. f[x] = min(f[i]+w[i, x]), i < x且w[i, x]满足单调性(即w[i, j]+w[i ...
- BZOJ4919 [Lydsy1706月赛]大根堆 【dp + 启发式合并】
题目链接 BZOJ4919 题解 链上的\(LIS\)维护一个数组\(f[i]\)表示长度为\(i\)的\(LIS\)最小的结尾大小 我们可以用\(multiset\)来维护这个数组,子树互不影响,启 ...