1

I am using xtensa-esp32-elf-8.2.0 toolchain for compilation (which is based on gcc 8). I also tried with xtensa-esp32-elf-5.2.0 toolchain (which is based on gcc 5). Both generate the same error message.

I have written a jumptable which has following instructions 10 times , which are basically used to jump at the particular address and execute particular instruction. But I am getting an error while compilation which is

Assembler Messages: Error: attempt to move .org backwards

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

I have surfed the web for the same but, either most of the pages do not provide viable answer or they say its a compiler version problem ( which I dont think is the right solution as I use latest toolchain )

Can somebody please help

example use of my jumptable:

    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
  • 2
    Please provide a [mcve]. – rustyx Oct 24 '19 at 09:12
  • What are you hoping `.org` will do; why are you using it at all? If you just want alignment to the next 16-byte boundary, use `.p2align 4`. If should be obvious that if you use `.org .LSAC_jumptable_base + (16 * 6)` more than once, at least the later ones will be trying to move the output position backwards to overwrite some instruction you already emitted, which the error message tells you GAS doesn't support. – Peter Cordes Oct 24 '19 at 09:40
  • Or if your compiler is inlining your asm block into multiple places in the same source file, that's another reason the same `.org` could appear twice. Perhaps `__attribute__((noinline,noclone))` on the function containing it? Look at the actual asm output file the compiler generated. – Peter Cordes Oct 24 '19 at 09:42
  • Use of the `.org` directive is almost always wrong. Instead, use linker scripts to put the jump table into the desired place. – fuz Oct 24 '19 at 09:49
  • @PeterCordes , I am using .org instruction to align the instructions (following .org) to an address which is .LSAC_jumptable_base + (16*6) so that in my assembly function wherever I type jx a2 ( a2 contains address .LSAC_jumptable_base + (16 *6) ) , it should jump to this address in the jumptable and then execute the written instructions. , I am using exact same table in one of my other assembly functions ( it has lower instructions ) it works fine . – flying_raijin Oct 24 '19 at 10:31
  • @rustyx PTAL at the example – flying_raijin Oct 24 '19 at 10:34
  • @fuz Any suggestions , how to do that ? , .org seems to be simplest and easy to understand and use! – flying_raijin Oct 24 '19 at 10:36
  • @flying_raijin Put your jump table into a separate section. Then, write a linker script that places this section into memory where you want it. Object files (as produced by the assembler) are relocatable. You cannot place data at fixed addresses using just the assembler (i.e. without a linker script) and the `.org` directive doesn't do that. Instead, it places data at a fixed place in the section which can be located wherever the linker wants. This is not what you expect `.org` to do. – fuz Oct 24 '19 at 10:41
  • 2
    StackOverflow works like this: you need to post a self-contained example, which when we compile, gives the same error. Without it we can only guess. Here's my guess: your code does not fit (the part that you never showed). – rustyx Oct 24 '19 at 11:19
  • @fuz: Actually I think that might be what the OP wants `.org` to do: like `.p2align` but to a specific distance from a symbol, not just the next multiple of 16. Then instead of an actual jump table (loading a pointer from memory), you can do a computed jump to an address that's `base + 16*n` – Peter Cordes Oct 24 '19 at 13:06
  • I think Rustyx's guess sounds likely, one of your blocks takes more than 16 bytes so there isn't enough room since the last `.org`. Try optimizing your code for size, or hoist some of it to before the dispatch branch. (e.g. ` mov a1, a0` is common.) – Peter Cordes Oct 24 '19 at 13:11
  • 1
    Your second source code sample shows two `.org` directives. The second one will try to move the output position back **if** the instructions in between take too many bytes. – the busybee Oct 25 '19 at 06:35

1 Answers1

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)

The code between the .orgs is supposed to fit into 16 bytes, but it will not fit unless the assembler relaxes some instructions in it: all used instructions are 3-byte long by default and there are 6 of them. But there are 2-byte variants for the mov and l32i instructions, so you can rewrite it as follows:

.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 instead of table that consists of chunks of code of fixed size it may be easier to have a table of addresses of entry points. So your example could be rewritten as follows:

.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
jcmvbkbc
  • 723
  • 1
  • 4
  • 5
  • The tradeoff between a jump table (with pointers in memory) vs. a purely computed jump (fixed-width code blocks) would depend on the microarchitecture. (But I know nothing about Xtensa). And with many entries, the jump needs extra storage per entry. Either way, you'd probably want to hoist or sink any independent common instructions out of the blocks and put them before or after jump, unless you need to schedule instruction for an in-order pipeline. e.g. the `mov a1, a0` and the `l32i` instructions look the same in both blocks. Maybe the OP had some different blocks they left out? – Peter Cordes Oct 26 '19 at 06:46
  • Actually the thing is, When I shifted all of this code in a different ``.S`` file then this error stopped. Is there any limit on what amount of code can you write in a ``.S`` file , and even if there is , it should have mentioned size limit exceeded. – flying_raijin Jan 16 '20 at 03:30
  • Thank You all for taking your time and answering to the question. – flying_raijin Jan 16 '20 at 03:31