【问题标题】:ARM asembly help for CortexMCortex M 的 ARM 汇编帮助
【发布时间】:2020-08-03 14:21:35
【问题描述】:

我需要制作一个 ASM 函数。 我完成了大部分工作,但我无法让它按应有的方式工作。 我想做一个运行到无穷大的循环,直到某个寄存器(SysTick->CTRL Flag)中的一点被设置。 我使用了 TST r5,#Val。 val 是 1

【问题讨论】:

  • 将循环的minimal reproducible example 复制/粘贴到您的问题中。如果您希望人们帮助调试您的代码,请显示您的确切代码。虽然一个问题是str r5, [r0,#0] 没有修改 r5,所以 IDK 你的意思是“来自”那个。也许您想将 MMIO 地址中的ldr 转换为r5
  • 另外,是的,您可以在 SO 答案中找到大量示例函数,以及编译简单 C 函数的 GCC 或 clang 输出,例如在godbolt.org 上(默认过滤指令,但您可以在下拉菜单中禁用它。)
  • 汇编语言是特定于汇编器的,听起来你在谈论 gnu 汇编器。如果不需要,则不需要 .section 文本,需要 .thumb_func (在条目标签之前)和文件(或 .global)某处的 .globl 。一个 bx lr 退出函数。语法 1
  • 而且你需要 .thumb 在有问题的代码之前的某个地方,否则它通常会构建为 arm(取决于我假设的工具配置方式)。无论如何,您应该不时在反汇编中检查它作为一般检查。 ESP 与 arm/thumb 和交互操作您要检查与其他代码混合的手写 asm 的反汇编。

标签: assembly arm cortex-m thumb


【解决方案1】:

首先,汇编语言是特定于汇编器的。

对于 gnu:

.thumb
.globl myfun
.thumb_func
myfun:
    ldr r0,=0x12345678
myfun_inner:
    ldr r1,[r0]
    cmp r1,#0
    bne my_fun_inner
    bx lr

so.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <myfun>:
   0:   4802        ldr r0, [pc, #8]    ; (c <myfun_inner+0xa>)

00000002 <myfun_inner>:
   2:   6801        ldr r1, [r0, #0]
   4:   2900        cmp r1, #0
   6:   d1fe        bne.n   0 <my_fun_inner>
   8:   4770        bx  lr
   a:   0000        .short  0x0000
   c:   12345678    .word   0x12345678

gnu 有一个有趣的奇怪标签快捷方式,我不是特别喜欢,但有些人喜欢:

.thumb
.globl myfun
.thumb_func
myfun:
    ldr r0,=0x12345678
1:
    ldr r1,[r0]
    cmp r1,#0
    bne 1b
    bx lr

将 1b 视为 1 向后,您可以在此代码中有多个 1:、2: 等标签,而 1b 或 1f 将引用最接近的 1:向前或向后。并产生相同的代码:

   6:   d1fe        bne.n   0 <my_fun_inner>

这是一个相对跳转,所以即使我已经反汇编了对象,当你链接和反汇编链接的二进制文件时,这将是相同的机器代码:

ldr r0,=0x12345678

是一些 ARM 汇编程序支持的伪代码。 Gas 尤其会尝试找到优化的解决方案:

.thumb
ldr r0,=0x12345678
ldr r0,=1
ldr r0,=0x20002

00000000 <.text>:
   0:   4802        ldr r0, [pc, #8]    ; (c <.text+0xc>)
   2:   f04f 0001   mov.w   r0, #1
   6:   f04f 1002   mov.w   r0, #131074 ; 0x20002
   a:   0000        .short  0x0000
   c:   12345678    .word   0x12345678

现在这有点危险,因为它选择了 thumb2 指令,所以您可能希望对 cortex-ms 超级通用(到目前为止,实际的 armv8m 芯片)

.cpu cortex-m0
.thumb
ldr r0,=0x12345678
ldr r0,=1
ldr r0,=0x20002

00000000 <.text>:
   0:   4801        ldr r0, [pc, #4]    ; (8 <.text+0x8>)
   2:   4802        ldr r0, [pc, #8]    ; (c <.text+0xc>)
   4:   4802        ldr r0, [pc, #8]    ; (10 <.text+0x10>)
   6:   0000        .short  0x0000
   8:   12345678    .word   0x12345678
   c:   00000001    .word   0x00000001
  10:   00020002    .word   0x00020002

其中的 .short 有一个对齐间距,以保持单词对齐。这是 binutils 的尖端版本,您有时/经常会看到一个 nop 放置在其中以填充空间。所以现在也许该工具正在填充零。

最小的完成应该是

.cpu cortex-m0
.thumb
.globl myfun
.thumb_func
myfun:
    ldr r0,=0x12345678
myfun_inner:
    ldr r1,[r0]
    cmp r1,#0
    bne my_fun_inner
    bx lr

如果你检查 gcc 的输出,你会看到一些更接近最大值的东西,还有更多的语法。因此,根据您的个人喜好,瞄准两者之间的某个地方。我经常不使用 .cpu,除非我需要,因为它过去默认为 armv4t,这几乎是“所有拇指变体”,但现在显然不是,所以我必须改变我的习惯。再次在这里,总是检查你的 asm 代码输出,尤其是在这个 arm arm/thumb 多个 thumb2 扩展,多个指令集使用相同的工具。

【讨论】:

  • 谢谢。正是我所需要的。抱歉,我没有发布我的代码。没有工作来获取它。我还看到你使用 CMP 进行 0.TEQ(平等测试)也可以?
  • 我故意不为您编写代码,这是一个带有循环的示例,而不是真实地址等。您可以为您的任务编写代码。 TST 是确定单个位是设置还是清除(结合 BNE 或 BEQ 取决于)的适当函数。正如我在评论中提到的,你应该在#0x10000 vs #(1
  • TEQ 是测试一个完整的值而不是一个位,是的 TEQ 可能在这里更好(例如),但 TEQ 仅支持 armv7-m(皮质-m3,m4,m7) 但不在 armv6-m (cortex-m0, cortex-m0+) 和一些已知的 armv8-ms (cortex-m23, cortex-m33) 上(因为 armv8-m 依赖于核心而不是架构) .根据您使用的语法数量或剪切和粘贴的内容,您最终可能会生成处理器不支持的指令并最终导致难以调试的故障。
  • 很多人会告诉你使用统一语法,我不会,我发现很难获得我想要的指令(至少使用 gnu),我倾向于所有拇指变体,这我倾向于只使用 cpu cortex-m0 来获取,但你需要形成自己的习惯和偏好,不要将自己局限于任何一种意见/一组偏好。
  • 非常感谢。你知道我如何才能看到我的程序集生成的指令吗?我在 Atmel Studio 7 上,但引擎盖下是 GCC。我想我可以在网上搜索“编译的 GCC 查看指令”。
猜你喜欢
  • 1970-01-01
  • 2015-03-10
  • 1970-01-01
  • 2017-06-07
  • 2015-04-20
  • 1970-01-01
  • 1970-01-01
  • 2019-11-13
  • 1970-01-01
相关资源
最近更新 更多