I am trying to chase down an exception within some previously existing ARM assembly code. The line in question is:
ldr x0, [x21, x19, lsl #3]
The result of the above equation is x0
having an invalid memory address, which subsequent code attempts to use.
I know the lsl
is performing a left shift 3, but I am not sure what it is actually performing the shift on. I haven't seen values to the left of a shift before. A shift is typically, value to be shifted, how far and it what direction. If the line above is using both x21 and x19, how are they being used in the shift? Is one of the registers the lower 32 bits and the other the upper 32?
x19
is currently 0x0
x21
is currently a value greater than 0x0
I cannot change the line above, but I can change the values of x19 & x21. Any help in interpreting this would be appreciated.
I have traced through the assembly code, found the values of all of the registers and searched the internet on how to decode the line in question
How to interpret memory reference on right side of assembly equation?
Not sure what you mean by assembly equation, so unclear what is on the right side of that.
If the instruction were to store (which relates to being on the left side of =
in C, as in a[i]=v
), the addressing mode would be in the same position in assembly, as in str x0, [x21, x19, lsl #3]
.
If the question is about the second register, x19
, that is an index, which is shifted, while the base, x21
is not.
I think you'll have better search results using the term addressing mode instead of assembly equation. See here, for example.
64-bit ARM has several indexed addressing modes.
In ldr x0, [x21, x19, lsl #3]
, the first register of the addressing mode, x21
, is expected to hold a 64-bit pointer. The second register in the addressing mode, x19
, holds an index. Here it is a 64-bit index, and it is also scaled by 8, via the lsl #3
, before being added to the (unscaled) value of the first register, to form the final memory access address.
The simplest use of this instruction would be as in the following:
long a[]; // perhaps as parameter, alternately, long *a;
long i; // some indexing variable
long v = a[i]; // accessing some element at index i of array a
So the type of a
is array of or pointer to long int (64-bit). The C language will automatically scale i
by 8, so we don't see that when we write it in C, though the machine code must do it.
In that v=a[i]
, the array's base address, a
, is in x21
, and the index i
is in x19
, while v
is x0
.
Among other things, the processor can also treat the indexing register as signed or unsigned 32-bit int instead of long, which is good for C code that chooses int
to be 32-bits.