【问题标题】:ROM vs RAM in ARM assembly and the AREA directiveARM 程序集中的 ROM 与 RAM 以及 AREA 指令
【发布时间】:2017-04-13 00:35:03
【问题描述】:

所以我为 TI 微控制器编译了一个简单的 ARM 程序集(特别是 THUMB)程序。我只是对 EQU 和 DCD 存储在内存中的位置(RAM 与 ROM)以及 AREA 指令如何与之相关感到困惑。我从这个开始:

Y1      EQU     0x23


        AREA    |.text|, CODE, READONLY, ALIGN=2
        THUMB

X2      DCD     0x23
Y2      EQU     0x23

    MOV R0, #0
    LDR R1, =X2
    STR R0, [R1]

        END

我假设由于 EQU 是恒定的,它们进入 ROM。但在这里,它们位于只读的代码部分(所以我假设它在 ROM 中)在没有 AREA 指令的部分中。我不确定那里的默认值是什么。

DCD 在 READONLY 部分中声明,但我仍然可以对其进行写入。

如果我将 DCD 添加到空白部分,则会收到错误消息:Area directive missing。如果我添加 AREA 指令,那么代码如下所示:

    AREA    |.data|, DATA

X1      DCD     0x23
Y1      EQU     0x23


        AREA    |.text|, CODE, READONLY, ALIGN=2
        THUMB
        EXPORT  Start

X2      DCD     0x23
Y2      EQU     0x23

Start
    MOV R0, #0
    LDR R1, =X1
    STR R0, [R1]
    MOV R0, #0
    LDR R1, =X2
    STR R0, [R1]

        END

EQU 和 DCD 无处不在,AREA 指令似乎根本不会影响我如何访问它们。此外,将 READONLY 添加到 AREA DATA 指令也没有效果。

【问题讨论】:

  • EQU 指令不分配任何内存,因此它不会“去”任何地方。它只是为符号分配一个值。 DCD 指令在当前部分为一个或多个 32 位字分配内存,使用给定值初始化字,然后分配分配给符号的第一个字的地址。 AREA 指令对 ROM 或 RAM 中是否有任何内容没有直接影响。这取决于如何配置链接器以将部分映射到 ROM 或 RAM。如果您写入 READONLY 部分,汇编器不会给出错误,并且 CPU 可能会忽略对 ROM 的任何写入。
  • 汇编语言特定于汇编器,即您正在使用的软件。您在这里使用什么汇编程序/软件? ARM 不是一个充分的答案,因为它不是一个软件程序,而是制造许多 cpu 内核的公司。
  • 如前所述,EQU 就像 C 中的定义一样,它没有存储空间,它只是程序中的 ascii 替代解决方案,在组装之前发生的搜索和替换。 DCD 确实分配了空间,但它在节内,您可以并且需要 .data 和 .text 中的数据项。在 .text 中,您需要例如不能立即加载的地址。正如您演示的 (ldr r1,=x2) 所展示的解决此问题的技巧,它在 .text 空间中为该地址分配一个 32 位数据项。 LINKING 确定 .text 和 .data 的位置,如果您愿意,它们都可以在 ram 中...
  • @old_timer 我正在使用 Keil uVision。另外,如果EQU只是程序中的一个替换,那我为什么要写LDR R0, =SomeEQULabel呢?它用什么代替标签?它不能放置整个立即数,因为它是 32 位的,而且 LDR 无论如何也不接受立即数
  • 使用其他汇编器你绝对可以使用 ldr r0,=0x12345678。你认为标签是什么?一个地址,一个 32 位地址,所以 ldr r0,=someaddress 只是说当你弄清楚我想要它在那个寄存器中的地址时,所以为我分配一个位置并用 pc 相对负载替换它。

标签: assembly arm thumb


【解决方案1】:

使用我可以访问的汇编程序,您提出的问题应该在两种汇编语言之间移植,因为许多问题是关于指令集而不是汇编语言。

.equ X1,0x12345678

.text
.thumb

.globl _start
_start:


ldr r0,=X1
ldr r1,=X2
ldr r2,[r1]
ldr r3,=Y4
ldr r4,=Y3
str r3,[r4]
bl bounce
mov lr,pc
ldr r5,=bounce
bx r5
b .
X2: .word 0xAABBCCDD

.thumb_func
bounce:
    bx lr
    nop

.data

Y3: .word 0
Y4: .word 0x11223344

组装链接和反汇编。

00001000 <_start>:
    1000:   4807        ldr r0, [pc, #28]   ; (1020 <bounce+0x4>)
    1002:   4908        ldr r1, [pc, #32]   ; (1024 <bounce+0x8>)
    1004:   680a        ldr r2, [r1, #0]
    1006:   4b08        ldr r3, [pc, #32]   ; (1028 <bounce+0xc>)
    1008:   4c08        ldr r4, [pc, #32]   ; (102c <bounce+0x10>)
    100a:   6023        str r3, [r4, #0]
    100c:   f000 f806   bl  101c <bounce>
    1010:   46fe        mov lr, pc
    1012:   4d07        ldr r5, [pc, #28]   ; (1030 <bounce+0x14>)
    1014:   4728        bx  r5
    1016:   e7fe        b.n 1016 <_start+0x16>

00001018 <X2>:
    1018:   aabbccdd    bge feef4394 <X1+0xecbaed1c>

0000101c <bounce>:
    101c:   4770        bx  lr
    101e:   46c0        nop         ; (mov r8, r8)
    1020:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000
    1024:   00001018    andeq   r1, r0, r8, lsl r0
    1028:   00002004    andeq   r2, r0, r4
    102c:   00002000    andeq   r2, r0, r0
    1030:   0000101d    andeq   r1, r0, sp, lsl r0

Disassembly of section .data:

00002000 <__data_start>:
    2000:   00000000    andeq   r0, r0, r0

00002004 <Y4>:
    2004:   11223344            ; <UNDEFINED> instruction: 0x11223344

Disassembly of section .ARM.attributes:

00000000 <.ARM.attributes>:
   0:   00001341    andeq   r1, r0, r1, asr #6
   4:   61656100    cmnvs   r5, r0, lsl #2
   8:   01006962    tsteq   r0, r2, ror #18
   c:   00000009    andeq   r0, r0, r9
  10:   01090206    tsteq   r9, r6, lsl #4

所以它把 ldr r0,=0x12345678 变成了这个

 1000:  4807        ldr r0, [pc, #28]   ; (1020 <bounce+0x4>)

还有这个

    1020:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

加载(32 位,因为它是 ldr,ldrb 将是 8(填充),ldrh 16 位(填充))获取前面两条指令的 pc,将 28 添加到 0x1000 + 4 + 28 = 0x1000 + 32 = 0x1000 + 0x20 所以他们在那个地址放置了数据 0x12345678。其他所有的东西也一样...

我本可以自己做,而不是依赖伪指令。

.text
.thumb

.globl _start
_start:

    ldr r0,xyz
    ldr r1,xyz_add
    ldr r2,[r1]
    b .

xyz: .word 0x12345678
xyz_add: .word xyz

未链接就足够了

00000000 <_start>:
   0:   4801        ldr r0, [pc, #4]    ; (8 <xyz>)
   2:   4902        ldr r1, [pc, #8]    ; (c <xyz_add>)
   4:   680a        ldr r2, [r1, #0]
   6:   e7fe        b.n 6 <_start+0x6>

00000008 <xyz>:
   8:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

0000000c <xyz_add>:
   c:   00000008    andeq   r0, r0, r8

因为我有它在同一部分,附近我可以直接加载 0x12345678 我不需要获取地址然后从地址加载基本上 =0x12345678 伪代码所做的。但是对于很远的事情,您仍然可以将数据项作为地址然后加载,然后从该地址加载(双重间接)。

.text
.thumb

.globl _start
_start:

    ldr r0,=0x11223344
    ldr r1,=5

至少使用一个汇编器,您可以对所有内容使用 =something 技巧,并且如果适合,汇编器有望进行优化。

00000000 <_start>:
   0:   4800        ldr r0, [pc, #0]    ; (4 <_start+0x4>)
   2:   2105        movs    r1, #5
   4:   11223344

如果它采用另一种方式会很好,如果你立即执行 mov ,如果它不适合它会加载 pc relative,但我不认为他们这样做。

现在把它翻译成你的汇编语言。 AREA 声明声明 .text 和 .data 链接器稍后定义它们的位置。一些链接器可以修改代码,而不仅仅是立即偏移,有些可以有时替换整个指令(根据需要蹦床掉一些链接器插入的代码)。在这种情况下,链接器将在节中为汇编器分配的数据位置填充地址。

您可以在 .text 和 .data 中拥有数据项,而 .text 数据项是只读的,无论是 const 表还是指向其他代码或部分中链接的事物的地址。链接器必须填写远程地址的东西,因为它们在汇编时没有被解析。

EQU 在历史上是 C 中简单定义的汇编语言版本

#define ABCD 0x12345678

在编译之前,搜索并用 0x12345678 替换 ABCD 的实例。汇编程序也是如此。与 C 不同,您可能无法做的不仅仅是搜索和替换,汇编器宏是不同的语法。但它类似于定义。

DCD、DCB 等就像 gnu 汇编程序中的 .word、.byte 一样,他们说我想在这里放一些原始数据或在这里为原始数据分配空间,不是指令而是数据,无论出于何种原因我想使用它。

如果汇编器有一个它尊重它的 READONLY 指令,如果它不是那会困扰我的希望。但与此同时,常用的名称 .text、.data 可能胜过这一点。

【讨论】:

  • 如果在搜索和替换之后,文字值不适合指令,它会执行相对于 PC 的加载,对吧(就像在您的 ldr r0,=0x11223344 示例中一样)?
  • 当然适用于 gnu 汇编程序。我不知道您正在使用的汇编语言...只需尝试汇编和反汇编,看看它的作用。或者另辟蹊径,做一个 mov r0,#SOMETHING 和 EQU 一些简单而不简单的常量,然后看看。
  • 请注意,ARM 立即编码很容易让您头疼,例如 8 或 9 个非零位,可以以两位为单位进行移位/旋转,例如 0xAB000000 或 0xB000000A 等。拇指直接编码更难缠住你的头,显然它们可以处理像 1 或 3 这样的数字,但其他的你必须去看看。
  • 是的,我查看了反汇编,似乎大 EQU 值(如 32 位值)被 DCD 写入内存位置,然后使用 PC 相对寻址来获取它。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-08
相关资源
最近更新 更多