0

我正在上这个关于微控制器的实验课(我们使用的是 FRDM-KL25Z128),但我在使用 .word 和 .equ 指令时遇到了问题。

首先,教授给我们的示例代码是为了让 FRDM 板上的红色 LED 闪烁,具体如下:http ://www.dca.fee.unicamp.br/cursos/EA871/2s2016/UW/codes/ exp2.s

在修改代码以使其同时闪烁三个 LED 并发出白光之前,我们需要回答一些问题,但这不是问题所在。

在代码的底部,所有寄存器地址都是用 .word 指令定义的(因为我们使用的是 32 位字)。问题之一是回答我们是否可以将指令 .word 替换为 .equ。

我的第一个想法是,是的,我可以用 .word 代替 .equ 因为最后一个指令是为标签分配一个常量值,并且由于我不想更改这些标签的值,所以 .equ 应该可以使用。

但是当我测试它时,通过评论这些行:

SIM_SCGC5: @ Endereço do SIM_SCGC5
.word 0x40048038

并写:

.equ SIM_SCGC5, 0x40048038

应该将值 0x40048038 分配给 SIM_SCGC5 标签。但是代码不起作用,我将在以下行中收到错误:

ldr     r3,SIM_SCGC5

说:

无效偏移,值太大

所以我不确定我是否搞砸了 .equ 指令,或者默认情况下 .equ 分配的值是否占用了 LDR 无法处理的更多位。

这里有什么问题?

一些注意事项:

  • 我开始用微控制器在汇编中编写代码,所以我仍然缺少很多信息,比如硬件限制。所以我可以在不知不觉中写一堆随机的单词。

  • 抱歉准备了这么久。我知道长帖子不是 Stack Overflow(或一般的 Stack Exchange)的最爱,但我不想在没有上下文的情况下提出问题。

4

2 回答 2

4

.word 在这里使用

ldr r0,hello
nop
nop
nop
hello: .word 0x12345678

类似于

unsigned int word = 0x12345678

你好:是一个标签。word与它无关。只是意味着我现在想为地址使用标签,可以在那里放置代码或数据或其他任何东西。就像 C 中的 unsigned int 一样,您在程序中分配了一些空间。

.equ 虽然就像定义你没有分配空间,但你只是为那个字符串定义了一些替换。

arm-none-eabi-as so.s -o so.o
arm-none-eabi-objdump -D so.o
...
00000000 <hello-0x10>:
   0:   e59f0008    ldr r0, [pc, #8]    ; 10 <hello>
   4:   e1a00000    nop         ; (mov r0, r0)
   8:   e1a00000    nop         ; (mov r0, r0)
   c:   e1a00000    nop         ; (mov r0, r0)
00000010 <hello>:
  10:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

如果我添加这个

.equ JELLO, 0x22
ldr r0,hello
nop
nop
nop
hello: .word 0x12345678

没有变化,如果我这样做

.equ JELLO, 0x12345678
ldr r0,JELLO

.equ 是一个类似于替换的定义。

ldr r0,0x12345678

so.s: Assembler messages:
so.s:2: Error: internal_relocation (type: OFFSET_IMM) not fixed up

现在如果我们想要 r0 中的 VALUE,那么这是一个语法问题。

mov r0,#0x12345678

我们在 ARM 中无法做到这一点,指令是 16 位或 32 位,仅此而已,因此您不能拥有 32 位立即数和操作码和寄存器等 32 位。所以必须给出一些东西,取决于指令集和变化的立即数在几到可能 11 或 13 位之间,正常的 arm mov 指令全尺寸 arm 指令,如 9 个有效位。

so.s: Assembler messages:
so.s:3: Error: invalid constant (12345678) after fixup

有趣的是,诀窍是返回加载并询问汇编程序,我想要标签的地址而不是标签上的东西。

ldr r0,=hello
nop
nop
nop
hello: .word 0x12345678
.word 0,1,2,3

汇编器为我们分配了一个字,它可以找到一个空格

00000000 <hello-0x10>:
   0:   e59f001c    ldr r0, [pc, #28]   ; 24 <hello+0x14>
   4:   e1a00000    nop         ; (mov r0, r0)
   8:   e1a00000    nop         ; (mov r0, r0)
   c:   e1a00000    nop         ; (mov r0, r0)
00000010 <hello>:
  10:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000
  14:   00000000    andeq   r0, r0, r0
  18:   00000001    andeq   r0, r0, r1
  1c:   00000002    andeq   r0, r0, r2
  20:   00000003    andeq   r0, r0, r3
  24:   00000010    andeq   r0, r0, r0, lsl r0

请注意,它没有将地址 0x10 处的东西加载到寄存器中,而是将地址 0x24 处的东西加载到它为我们添加的位置,并且在该位置它向 hello 提供地址 0x10,因此 r0 将获得 0x10 而不是0x12345678 通过添加等号。有点像在 C 中删除一维指针上的星号,你得到的是指针的地址,而不是指针指向的东西。

所以知道这个 ldr rx,=something 意味着我想要那个标签的地址,如果我们只是放一个地址而不是代表地址的标签呢?

ldr r0,=0x87654321
nop
nop
nop
hello: .word 0x12345678
.word 0,1,2,3

它恰好起作用

0000000 <hello-0x10>:
   0:   e59f001c    ldr r0, [pc, #28]   ; 24 <hello+0x14>
   4:   e1a00000    nop         ; (mov r0, r0)
   8:   e1a00000    nop         ; (mov r0, r0)
   c:   e1a00000    nop         ; (mov r0, r0)
00000010 <hello>:
  10:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000
  14:   00000000    andeq   r0, r0, r0
  18:   00000001    andeq   r0, r0, r1
  1c:   00000002    andeq   r0, r0, r2
  20:   00000003    andeq   r0, r0, r3
  24:   87654321    strbhi  r4, [r5, -r1, lsr #6]!

因此,这并不能证明您可以在任何您想要的基于 gnu 汇编器的指令集中盲目地将 .word 替换为 .equ,但是由于运气不佳,您几乎可以通过修复语法来实现

.equ JELLO,0x12345678
ldr r0,=JELLO
nop
nop
nop

你去吧

00000000 <.text>:
   0:   e59f0008    ldr r0, [pc, #8]    ; 10 <JELLO-0x12345668>
   4:   e1a00000    nop         ; (mov r0, r0)
   8:   e1a00000    nop         ; (mov r0, r0)
   c:   e1a00000    nop         ; (mov r0, r0)
  10:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

通常,对于任何/其他指令集 .word 到 .equ 的负载,您需要更改为 mov

.equ JELLO,0x12
ldr r0,hello
mov r0,#JELLO
nop
nop
nop
hello:
.word 0x12


00000000 <hello-0x14>:
   0:   e59f000c    ldr r0, [pc, #12]   ; 14 <hello>
   4:   e3a00012    mov r0, #18
   8:   e1a00000    nop         ; (mov r0, r0)
   c:   e1a00000    nop         ; (mov r0, r0)
  10:   e1a00000    nop         ; (mov r0, r0)
00000014 <hello>:
  14:   00000012    andeq   r0, r0, r2, lsl r0

使用 x86 中的任何语法(mov、move 等你好语法也许))

注意我使用的是上面的遗留 gnu 汇编器语法,所以使用它

.equ JELLO,0x12
mov r0,JELLO

so.s: Assembler messages:
so.s:4: Error: immediate expression requires a # prefix -- `mov r0,JELLO'

但是如果我们使用统一的语法,我想它不再关心井号了。

.syntax unified
.equ JELLO,0x12
mov r0,JELLO
mov r0,#JELLO

00000000 <.text>:
   0:   e3a00012    mov r0, #18
   4:   e3a00012    mov r0, #18

不是粉丝,应该让它更容易(更懒惰),只是让它变得更糟......这就是为什么我很少使用它,除非我必须......YMMV。

于 2016-08-31T02:14:49.140 回答
2

.word将 4 个字节组装到当前位置的输出文件中。如果您希望将数据存储在那里,则必须从放置它的地址加载它。如果在它前面放一个标签,符号的值就是地址。

.equ定义一个汇编时常量,用作将来表达式中的值。符号的值是常量,在目标文件中没有地址,也没有字节。因此,您可以将定义的内容.equ用作其他指令的立即操作数,例如add. 您不能将其与负载/存储一起使用。


将立即常数放入寄存器不同于从固定地址加载。 用于ldr r3, =SIM_SCGC5让汇编器生成它认为最好在 r3 中生成该常数的任何指令序列。他们混淆地为这个伪操作选择了与实际加载指令相同的助记符。

另请参阅为什么在 ARM 汇编中使用 LDR 而不是 MOV(反之亦然)?. 这可能是现有 SO 问题的副本,但我还没有找到理想的 dup 目标。

SIM_SCGC5.equ指令定义时,ldr r3, SIM_SCGC5我认为尝试从该绝对地址加载。您得到的错误是因为无法将其编码为单个指令。

如果可能,它将使用movmovn使用移位/旋转的立即数,否则会从附近的常量池回退到 PC 相对负载。我认为设置低 16 位和高 16 位的两条指令也是可能的。

另请参阅ARM 上的常量,以及Arm cortex-m3 mov 和 ldr等各种 SO 问题。

于 2016-08-31T01:12:53.510 回答