说说ARM汇编的LDR伪指令

原创 2008年04月27日 17:20:00


    我们知道ARM CPU中有一条被广泛使用的指令LDR,它主要是用来从存储器(确切地说是地址空间)中装载数据到通用寄存器。但不论是ARMASM还是GNU ARM AS,都提供了一条与之同名的伪指令LDR,而在实际中使用该伪指令的情况也较多,那他们有什么不同呢?下面我谈谈我的理解。

    由于我使用GNU工具链,所以以下的内容都以GNU AS的ARM语法为准。

    LDR伪指令的语法形式如下:
       LDR <reg>, = <constant-expression>

    这个常量表达式<constant-expression>中可以包含Label(在ARM汇编中Label会在连接时解释为一个常数),且其中的常数前不加#符号。

    范例demo.s:

.equ    STACK_BASE0x0c002000
.equ    STACK_SIZE0x00001000

.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    spsp#
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:

00000000 <.text>:
   
0:   e59fd004        ldr     sp, [pc, #4]    ; c <.text+0xc>
   
4:   e59fa004        ldr     sl, [pc, #4]    ; 10 <.text+0x10>
   
8:   e59ff004        ldr     pc, [pc, #4]    ; 14 <.text+0x14>
   c:   0c002000        stceq   
0, cr2, [r0]
  
10:   0c001000        stceq   0, cr1, [r0]
  
14:   00000000        andeq   r0, r0, r0
Disassembly of section .data:

    由于entry还没连上目标地址,objdump反汇编会认为是0,我们先不管它。另外两条LDR伪指令变成了实际的LDR指令!但目标很奇怪,都是[pc, #4]。那好我们看看[pc, #4]是什么。

    我们知道pc中存放的是当前指令的下下条指令的位置,也就是. + 8。那么上面的第一条指令ldr sp, [pc, #4]中的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
       ...
    原因不详。

LDR指令

LDR指令的格式:  LDR{条件}   目的寄存器     作用:将 存储器地址 所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中。 LDR指令的寻址方式比较灵活,实例如下: ...
  • tanyouliang
  • tanyouliang
  • 2011年09月11日 10:26
  • 51622

ARM的六大类指令集---LDR、LDRB、LDRH、LDM、STR、STRB、STRH、STM

汇编指令:LDR、LDRB、LDRH、STR、STRB、STRH
  • u013477200
  • u013477200
  • 2016年02月23日 15:30
  • 17382

MOV指令、LDR指令、LDR伪指令之间的区别

1、MOV指令 MOV指令可以把立即数或者寄存器内容(注意:这里绝对不可以是内存!!)传递给一个寄存器。  立即数相当于高级语言中的常量(常数), 立即数就是数字嘛,表示数值的数字, 存储器...
  • qingkongyeyue
  • qingkongyeyue
  • 2016年08月18日 11:36
  • 1673

WIN7_LDR_DATA_TABLE_ENTRY结构(x86 x64)

typedef struct _LDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks...
  • baidu_36226689
  • baidu_36226689
  • 2017年04月17日 18:56
  • 666

ARM体系结构和编程pdf

  • 2009年03月15日 22:16
  • 18.12MB
  • 下载

关于LDR指令的理解

之前在阅读arm的汇编代码时,碰到了adr指令,查arm的指令手册,只说该指令是采用相对地址的,但这个相对地址应该怎么理解,却没有具体说明。之后在网上以adr指令为关键字进行搜索,也没有找到进一步的知...
  • zzsfqiuyigui
  • zzsfqiuyigui
  • 2013年08月11日 18:12
  • 2824

ARM指令集--ldr、mov与str的用法与区别

ARM指令集–ldr、mov与str的用法与区别ARM 是 RISC 结构,因此只能使用精简指令。1. mov的用法在ARM体系中,mov只能用于数据在寄存器之间的移动或者往寄存器中写入立...
  • HorizontalView
  • HorizontalView
  • 2016年03月01日 16:38
  • 4683

ARM LDR汇编指令

ARM指令集中,LDR通常都是作加载指令的,但是它也可以作伪指令。 (1) LDR r0,=name,像这种带等号的是伪指令,而不是ARM指令,LDR 伪指令用于加载立即数或一个地址值到指定寄存...
  • gx19862005
  • gx19862005
  • 2014年06月27日 11:23
  • 1121

ARM汇编中LDR伪指令和LDR指令

ARM汇编中ldr伪指令和ldr指令           ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令。比如想把数据从内存中某处读取到寄存器中,...
  • ce123
  • ce123
  • 2012年01月07日 13:54
  • 16219

arm 汇编指令:内存访问方式 、STR 、LDR 指令

STR(立即数,thumb) STR(理解树
  • eibo51
  • eibo51
  • 2014年07月03日 23:09
  • 3420
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:说说ARM汇编的LDR伪指令
举报原因:
原因补充:

(最多只允许输入30个字)