【问题标题】:Assembler messages: Error: attempt to move .org backwards汇编程序消息:错误:尝试向后移动 .org
【发布时间】:2020-02-20 13:57:40
【问题描述】:

我正在使用 xtensa-esp32-elf-8.2.0 工具链进行编译(基于 gcc 8)。 我还尝试了 xtensa-esp32-elf-5.2.0 工具链(基于 gcc 5)。两者都生成相同的错误消息。

我已经写了一个跳转表,它有 10 次以下指令,基本上是用来跳转到特定地址并执行特定指令。但是我在编译时遇到错误

汇编程序消息: 错误:尝试向后移动 .org

    .org    .LSAC_jumptable_base + (16 * 6)
    mov     a6, a4
    l32i    a2, sp, 0x08
    l32i    a4, sp, 0x10
    mov     a1, a0
    rsr     a0, excsave1
    rfe

我也上网过同样的问题,但是大多数页面都没有提供可行的答案,或者他们说这是编译器版本问题(我认为这不是正确的解决方案,因为我使用的是最新的工具链)

有人可以帮忙吗

我的跳转表的使用示例:

    movi    a3, .LSAC_jumptable_base
    l32i    a0, sp, 0
    addx8   a2, a2, a3      // a2 is now the address to jump to
    l32i    a3, sp, 0x0c

    jx      a2

    .org    .LSAC_jumptable_base + (16 * 5)
    mov     a5, a4 //Here, a4 is the correctly read value
    l32i    a2, sp, 0x08
    l32i    a4, sp, 0x10
    mov     a1, a0
    rsr     a0, excsave1
    rfe

    .org    .LSAC_jumptable_base + (16 * 6)
    mov     a6, a4
    l32i    a2, sp, 0x08
    l32i    a4, sp, 0x10
    mov     a1, a0
    rsr     a0, excsave1
    rfe

【问题讨论】:

  • 你希望.org做什么;你为什么要使用它?如果您只想对齐到下一个 16 字节边界,请使用 .p2align 4。如果应该很明显,如果您多次使用.org .LSAC_jumptable_base + (16 * 6),至少后面的那些将尝试向后移动输出位置以覆盖您已经发出的一些指令,错误消息告诉您GAS不支持。
  • 或者,如果您的编译器将您的 asm 块内联到同一源文件中的多个位置,这也是同一 .org 可能出现两次的另一个原因。也许__attribute__((noinline,noclone)) 在包含它的函数上?查看编译器生成的实际 asm 输出文件。
  • StackOverflow 的工作原理是这样的:您需要发布一个独立的示例,当我们编译时,它会给出相同的错误。没有它,我们只能猜测。这是我的猜测:您的代码不适合(您从未展示过的部分)。
  • 您的第二个源代码示例显示了两个 .org 指令。第二个将尝试将输出位置向后移动如果之间的指令占用太多字节。

标签: c assembly inline-assembly gnu-assembler xtensa


【解决方案1】:
.org    .LSAC_jumptable_base + (16 * 5)
mov     a5, a4 //Here, a4 is the correctly read value
l32i    a2, sp, 0x08
l32i    a4, sp, 0x10
mov     a1, a0
rsr     a0, excsave1
rfe

.org    .LSAC_jumptable_base + (16 * 6)

.orgs 之间的代码应该适合 16 个字节,但除非汇编程序放宽其中的一些指令,否则它将不适合:所有使用的指令默认都是 3 字节长,其中有 6 个。但是 mov 和 l32i 指令有 2 字节的变体,因此您可以将其重写如下:

.org    .LSAC_jumptable_base + (16 * 5)

_mov.n  a5, a4 //Here, a4 is the correctly read value
_l32i.n a2, sp, 0x08
_l32i.n a4, sp, 0x10
_mov.n  a1, a0
rsr     a0, excsave1
rfe

.org    .LSAC_jumptable_base + (16 * 6)

OTOH 而不是由固定大小的代码块组成的表,它可能更容易拥有入口点地址表。所以你的例子可以改写如下:

.section ".rodata", "a"
.align 4
.LSAC_jumptable_base:
.word   .L0, .L1
.previous

movi    a3, .LSAC_jumptable_base
l32i    a0, sp, 0
addx4   a2, a2, a3      // a2 is now the address in the table
l32i    a2, a2, 0       // a2 is now the address to jump to
l32i    a3, sp, 0x0c

jx      a2

.L0:
mov     a5, a4 //Here, a4 is the correctly read value
l32i    a2, sp, 0x08
l32i    a4, sp, 0x10
mov     a1, a0
rsr     a0, excsave1
rfe

.L1:
mov     a6, a4
l32i    a2, sp, 0x08
l32i    a4, sp, 0x10
mov     a1, a0
rsr     a0, excsave1
rfe

【讨论】:

  • 跳转表(在内存中有指针)与纯计算跳转(固定宽度代码块)之间的权衡取决于微架构。 (但我对 Xtensa 一无所知)。由于条目很多,跳转需要每个条目额外的存储空间。无论哪种方式,除非您需要为有序管道安排指令,否则您可能希望从块中提升或接收任何独立的通用指令并将它们放在跳转之前或之后。例如mov a1, a0l32i 指令在两个块中看起来相同。也许 OP 遗漏了一些不同的块?
  • 实际上,当我将所有这些代码转移到不同的.S 文件中时,这个错误就停止了。在.S 文件中可以写入多少代码是否有任何限制,即使有,也应该提到超出大小限制。
  • 感谢大家抽出宝贵时间回答问题。
猜你喜欢
  • 2020-11-13
  • 2019-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-12
  • 1970-01-01
  • 2017-05-13
相关资源
最近更新 更多