首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ARM装配中的LDR和EQU

ARM装配中的LDR和EQU
EN

Stack Overflow用户
提问于 2020-06-24 20:41:00
回答 2查看 2K关注 0票数 0

这是我的组装代码。

代码语言:javascript
复制
a EQU 0x20000000 
b EQU 0x20000004 
c EQU 0x20000008 
LDR R4, =a 
LDR R0, [R4] 
LDR R4, =b 
LDR R1, [R4] 
LDR R4, =c 

我有两个问题。在LDR R0, [R4]之后,R[4]里面是什么?0x20000000还是0x20000000的内存内容?

第二,在最后一行之后,R4c0x20000008中的内存内容是什么?

我在网上搜索过EQU和LDR,我自己的猜测是,对于所有的问题,它都是记忆的内容,但我很困惑,因为我的朋友说不行,我上面提到的十六进制数字存储在R[4]中。

更新:对不起,我想说的是:在LDR R0, [R4]之后,R0内部发生了什么?0x200000000x20000000的内存内容

R40x20000008还是0x20000008中的内存内容?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-06-24 21:55:14

首先,没有必要搜索整个互联网,直接到源代码,arm文档涵盖指令集。根据说明,这是手臂或拇指代码,但不是aarch64,所以假设手臂.

下一步是EQU是一个指令,而不是一个应该相当明显的指令,处理器将如何在汇编语言中使用变量和这样的指令?他们不会。

下一件事是汇编语言是由汇编程序定义的,你使用的工具不是目标(指令集)。这看起来可能是ARM的汇编器之一。许多人使用gnus工具,两者都能工作。我有gnu,所以汇编语言更改为:

代码语言:javascript
复制
.EQU a, 0x20000000
.EQU b, 0x20000004
.EQU c, 0x20000008
LDR R4, =a
LDR R0, [R4]
LDR R4, =b
LDR R1, [R4]
LDR R4, =c

对于gnu汇编程序,我先组装,然后反汇编,然后得到以下内容:

代码语言:javascript
复制
arm-none-eabi-as so.s -o so.o
arm-none-eabi-objdump -D so.o

so.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <.text>:
   0:   e3a04202    mov r4, #536870912  ; 0x20000000
   4:   e5940000    ldr r0, [r4]
   8:   e3a04242    mov r4, #536870916  ; 0x20000004
   c:   e5941000    ldr r1, [r4]
  10:   e3a04282    mov r4, #536870920  ; 0x20000008

类型语法是伪代码,因此不是真正的指令内容,因此汇编程序会有所不同。正如本页面其他部分所指出的,对该特性的支持是依赖于工具的,一些工具处理它的方式与其他工具不同。Gnu汇编程序,似乎最具特色的rich....let me digress...The寄存器是32位,指令是32位,不可能用32位立即加载指令和32位(固定长度)指令--没有其他位了。不同的(固定长度)指令集解决这种不同的方式,arm有它的解决方案是有趣的,并且在arm,拇指和thumb2扩展之间变化,对于arm,您可以有多达8个非零位,可以旋转一个偶数位,使immediate....gnu汇编程序将尽最大努力选择mov或mvn,如果它可以,否则它会创建一个pc相对负载,并将该值放置在附近的池。

在您的例子中,这些常量都工作得很好,因此mov被替换为ldr =伪指令。

代码语言:javascript
复制
   0:   e3a04202    mov r4, #536870912  ; 0x20000000
   4:   e5940000    ldr r0, [r4]
   8:   e3a04242    mov r4, #536870916  ; 0x20000004
   c:   e5941000    ldr r1, [r4]
  10:   e3a04282    mov r4, #536870920  ; 0x20000008

因为您应该已经在arm文档中阅读过了(如果没有方便的处理器供应商提供的文档,您就无法开始学习/阅读程序集)。ldr r0,r4的意思是将r4中的位作为地址使用(在r4中放置了0x20000000的先前指令,因此对于这个指令0x20000000成为一个地址),从该地址读取(加载)并将结果(返回的位)放在r0中。

作示范用途

代码语言:javascript
复制
.EQU a, 0x20000004
.EQU b, 0x20000200
.EQU c, 0x20000008
LDR R4, =a
LDR R0, [R4]
LDR R4, =b
LDR R1, [R4]
LDR R4, =c

给出

代码语言:javascript
复制
00000000 <.text>:
   0:   e3a04242    mov r4, #536870916  ; 0x20000004
   4:   e5940000    ldr r0, [r4]
   8:   e59f4004    ldr r4, [pc, #4]    ; 14 <a-0x1ffffff0>
   c:   e5941000    ldr r1, [r4]
  10:   e3a04282    mov r4, #536870920  ; 0x20000008
  14:   20000200

0x20000004可以旋转,你可以旋转0x00000042,例如,围绕偶数位旋转,这看起来像他们所做的。但是,不能根据mov或mvn指令的规则创建0x20000200,因此在附近使用了值0x20000200的pc相对负载。由于这不是完整的代码,处理器会像指令一样大量地输入数据,直到最终崩溃或幸运地陷入循环。对于真正的代码,该池将放置在某种类型的无条件分支之后和/或您告诉它的地方,该池基于汇编程序特定的汇编语言指令。

从技术上讲,arm汇编程序的汇编语言不必支持ldr r0,r4语法汇编程序作者可以自由地做他们想做的任何事情-- ldr r0,(r4),ldr r4,r0 loadw r0,0(r4),bob泡菜,洋葱,只要它生成正确的机器代码,它就是生成arm指令的汇编语言,因此也是arm汇编语言。到目前为止,我使用的所有汇编程序都按照这个顺序支持ldr r0,r4语法,但我认为并不是所有的人都支持=address,而且根据这里的经验,并不是所有的人都支持它。

您可以自己加载,但也可以使用汇编语言特定的差异:

代码语言:javascript
复制
.EQU a, 0x20000000
.EQU b, 0x20000000
.EQU c, 0xFFFFFF20
LDR R4, avalue
LDR R0, [R4]
LDR R4, =b
LDR R1, [R4]
LDR R4, =c
avalue: .word a

Disassembly of section .text:

00000000 <avalue-0x14>:
   0:   e59f400c    ldr r4, [pc, #12]   ; 14 <avalue>
   4:   e5940000    ldr r0, [r4]
   8:   e3a04202    mov r4, #536870912  ; 0x20000000
   c:   e5941000    ldr r1, [r4]
  10:   e3e040df    mvn r4, #223    ; 0xdf

00000014 <avalue>:
  14:   20000000

这迫使pc的相对负载,因为这是我所要求的。在arm目标中,一些汇编语言希望冒号标记标签,其他语言则看不到EQU差异(EQU类似于C#中简单的#define,在C中定义了0x2000000,但与C不同,您不使用它来处理更复杂的宏,可能会有特定于汇编程序的宏语言部分)。大多数正常的汇编程序使用冒号来标记注释,对于arm的gnu则不这样做(请注意,gnu汇编语言并不都必须在不同的目标上都有共同的规则/特性,假设每个目标都是由不同的人编写和维护的,因此每种语言对于评论和其他非指令性的东西都是不同的。如果它们是重叠的,那就这样吧。

这是不链接的,所以这个工具的反汇编从0开始,一旦链接,这个反汇编输出就会有不同的地址,但是位置无关( pc相对负载是……计算机代码将保持原样(对于这些示例)。

EQU是一个类似于C中定义的指令,它允许您使用0x20000000的值,而不是键入变量或名称或字符串a,而预处理程序将搜索并用0x20000000替换字母a的明显用法(当然,它不会替换a in add r0、r1、r2 )。

LDR是一个指令族LoaD寄存器。提供位于寄存器中的地址、可能的偏移量和目标寄存器。LDR R0,R4的意思是r4包含地址(在您的例子中是0x20000000),而r0是保存加载结果的目标寄存器。

ARM制造核心而不是芯片,没有理由假设0x20000000是“内存”--它可能是一个外围设备,处理器不关心,它只是一个它放在总线上的地址,芯片供应商知道这个地址意味着什么,并在总线上返回一个值。处理器不知道它是内存还是其他东西。

正如所写的,假设这不是某种破坏事物的奇怪的汇编程序,第一个ldr从地址0x20000000加载,并将结果放在r0中。

票数 2
EN

Stack Overflow用户

发布于 2020-06-24 20:54:30

前3行定义地址--这些地址可以存储在内存中的本地池中,但由于它们非常简单,汇编程序可能在第一次使用时使用几个MOV指令来组装它们。

第4行将R4设置为宏a -> 0x20000000的值(可能通过带有shift操作的MOV,但如果汇编程序出于某种原因希望从内存池加载)。

第5行从0x20000000的内存中读取,并将从内存中读取的值放入R0

第6行用R4加载0x20000004 (可能成为MOVADD)

第7行从0x20000004的内存中读取值,并将值放入R1,最后一行用0x2000008加载R4 (可能成为MOVADD)。

简而言之,LDR R4, =指令只加载寄存器中存储在EQU语句中的地址。后面的R0/R1负载是它们所指向的地址中的负载。

现在,如果真正了解程序集的人正在编写这个程序集,那么它可能只会变成2个指令:一个MOV of 0x2,它将转换为R4,以及一个处理负载和增量的LDM指令。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62563750

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档