2

I wanted to know if there was a way to load, say an array of words stored in memory, into an array of registers.

I know ldm can be used to load many registers at once, but my understanding is that you need to provide it with a register that already holds the first element.

Is there some pseudo-instruction that can help? Something like ldm =array, {r0,r1,r2} (fashioned after the actual pseudo-instruction ldr).

Thanks in advance!

Luis Sosa
  • 140
  • 8
  • On recent ARM there's `ldp` that loads a pair of registers. Not sure if `ldm` is possible with a nearby PC-relative addressing mode. If the data is farther away you need the label address in a register anyway. You could just use the last register to be loaded as the scratch reg for the address. – Peter Cordes Oct 03 '19 at 06:16
  • @PeterCordes I think that the `ldm` will load the source to an internal load/store pipe register so clobbering it with a load inside the target list is ok. The issue is with write back. It is a bit non-sensical to load the register from memory **AND** write back the end value. But the OP doesn't want this. I wouldn't be surprised if some ARM somewhere didn't support `ldm rN, {...,rN}` but it is suppose to work. – artless noise Oct 05 '19 at 16:05
  • @artlessnoise: Yeah, I was picturing using `ldm` *without* write-back for overwriting the address register. If that's possible. (And since I mentioned the possibility in my first comment, PC-relative `ldm` is not possible. Instead of a displacement, the instruction uses that space in the instruction word for the bitmap of which registers to load. Thanks for the reminder that ldm needs a pointer in a register, not a normal addr mode.) – Peter Cordes Oct 05 '19 at 16:22

1 Answers1

1

See: Getting a label to a register

There are four ways to get a label in traditional ARM,

 target:
     .long 0xfeadbeef, 0xdeadfeed, 0xbaddad00
  1. adr r0,target
  2. adrl r0,target
  3. ldr r0,=target
  4. sub r0,pc,#(.+8-target)

Thumb2 adds the movw movt combo, but that doesn't work for your use case.

Item 1,2,4 are basically the same. The item 3 adds an address as a constant to the literal pool and this address is loaded to the register. Something in 'C' like.

int variable;
const int *p = &variable;
int *reg = p; /* load register from memory */

Is there some pseudo-instruction that can help? Something like ldm =array, {r0,r1,r2} (fashioned after the actual pseudo-instruction ldr).

There are no pseudo-op for this; you must directly code things.

Given the 'target' definition above with three values, you can do this with...

 target:
     .long 0xfeadbeef, 0xdeadfeed, 0xbaddad00
 adr  r0, target
 ldm  r0, {r0-r2}  ; r0 as source/dest should work without write back
                   ; ldm r0, {r1-r3} maybe safer.

The pseudo-ops aren't implemented as this is 'rare' and the ldm is restrictive and doesn't support offsets of PC as a source. Something like,

 ; I just thunk it.
 ldm pc, {r0-r2,pc}  ; pc is always '8' ahead, assuming arm mode.
 nop
 .long arg0, arg1, arg2, routine

maybe possible but is restrictive as the data has to be positioned with the code and the control flow is also restrictive. Again this is a rare use case and the pseudo-op is to make it much easier to get arbitrary constants into registers which is commonly needed. So there are only direct coding of ldm commands. It is possible that some ARM CPU/architechure doesn't support having the same register as a destination; definitely not supported with write back (rN!). It depends on the class of ARM CPUs you are targeting. Using the PC as the source is probably even more unlikely to work over a large class of ARM CPUs. I would recommend the first example (rN != r15) unless you are running out of registers and on a known SOC/specific ARM CPU.


The ldrd instruction is a restrictive double word load but the source has more flexibility. You can use it to load two values without needing a separate adr. For example,

ldr r0, r1, [pc, #offset]

But it is limited to two registers. The target register need to be consecutive and the first is rN where N % 2 is zero or N is even.

artless noise
  • 21,212
  • 6
  • 68
  • 105
  • 1
    `ldm` isn't really a pseudo-op, it's a real machine instruction. Unless you mean in the sense of being [an alias for `ldmia`](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABCAEDD.html). The manual does say write-back is optional, but also says "**Rn must not be PC**". (At least on Cortex-M3, which is what google turned up for `ldm ldmia`). But also that *reglist must not contain Rn if you specify the writeback suffix.* which is makes it explicit by implication that *without* write-back you can safely overwrite the address register. (Again, docs for Cortex-M3) – Peter Cordes Oct 05 '19 at 16:30