7

I want to load 1 32 bit hexadecimal directly into a register using arm assembly.

mov r1,#0x6c617669

This cannot be used because from this instruction we can only load 8 bit values. So I have load the 32 bit value directly from the memory. So how can I store the 32 bit value in memory and load it directly to a register using arm assembly?

I tried this code.

    .global main
main:
    sub sp,sp,#4
    str lr,[sp,#0]

    sub sp,sp,#4
    str r0,x
    add sp,sp,#4

    ldr lr,[sp,#0]
    add sp,sp,#4
    mov pc,lr

    .data
x: .word 0x6c617669

But gives the following error.

test1.s: Assembler messages: 
test1.s:45: Error: internal_relocation (type: OFFSET_IMM) not fixed up
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
wageesha
  • 99
  • 1
  • 1
  • 6

3 Answers3

12

You have two basic choices. You can load it or build up the register 8 non-zero bits at a time

mov r0,#0x12000000             @ construct from 8-bit rotated immediates
orr r0,r0,#0x00340000
orr r0,r0,#0x00005600
orr r0,r0,#0x00000078
...

ldr r1,=0x12345678             @ let the assembler figure out how
...

ldr r3,myconst                 @ explicitly load from a nearby constant
...
myconst: .word 0x12345678

The latter two are the same, the equals trick simply asks the assembler to place the value within reach and do a pc relative load.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
old_timer
  • 69,149
  • 8
  • 89
  • 168
  • thumb mode you should just use a load. – old_timer Aug 01 '16 at 01:38
  • Your first solution is wrong, MOV (immediate) only accept an 8-bit immediate value maximum, you can not load 0x12000000 into r0. – Dr. Ehsan Ali Apr 16 '20 at 22:50
  • 1
    @Ehsan are you thinking thumb not arm? Even thumb has a rotation scheme in the encoding. mov r0,#0x12000000 is a perfectly valid arm instruction, mov, orr, etc all work the same. 1001 is four bits and that can be rotated by any power of two by the shifter before going into the register so it is perfectly valid as is 0x81 and 0xFF, etc but 0x102 is not 10000001 despite there being 8 significant bits the rotation is one bit so that wont work but 0x204 is valid. 10000001 8 bits rotated by a power of 2. 0x408 isnt and so on... – old_timer Apr 17 '20 at 00:34
  • e3a00412 mov r0, #301989888 ; 0x12000000 – old_timer Apr 17 '20 at 00:39
  • e380070d orr r0, r0, #3407872 ; 0x340000 – old_timer Apr 17 '20 at 00:39
  • for the 0x12000000 case the assembler chose to rotate 0x12 right 8 bits, there are other possible encodings for that for the 0x34 case 1101 the assembler chose to encode that as 0xD rotated right 14 bits, there are also alternate encodings for that – old_timer Apr 17 '20 at 00:41
  • 0x12, 00010010 so either 00010010 rotated right 8 or 01001000 rotated right 10. 00110100 so 00001101 rotated right 14 or 00110100 rotated right 16 or 11010000 rotated right 18. – old_timer Apr 17 '20 at 00:43
  • e3a00548 mov r0, #301989888 ; 0x12000000 different encoding same functionality – old_timer Apr 17 '20 at 00:45
  • thumb is limited to an 8 bit value no shift, thumb2 is a strange one... – old_timer Apr 17 '20 at 00:47
  • f04f 5090 mov.w r0, #301989888 ; 0x12000000 – old_timer Apr 17 '20 at 00:48
  • f04f 2012 mov.w r0, #301994496 ; 0x12001200 – old_timer Apr 17 '20 at 00:48
  • patterns like that are where it gets interesting always have to refer to the docs for that. but if you use the ldr rx,= pseudo instruction gas fills it in with the cheapest solution a mov or mvn if it can – old_timer Apr 17 '20 at 00:49
  • e3a00212 mov r0, #536870913 ; 0x20000001 yet another perfectly valid constant... – old_timer Apr 17 '20 at 00:56
3

Depending on your processor you may be able to use another set of instructions (i.e., movw & movt). For example, the instructions below will not work on Raspberry Pi 2 using GCC; however, they will work on the Marvell Armada 370/XP; which, if I recall correctly, is a Cortex-A9

movw r1, #0x6c61
movt r1, #0x7669

...

r1 0x6c617669 1818326633
InfinitelyManic
  • 760
  • 1
  • 6
  • 13
0

You can do it in another way, indirectly instead of directly:

.data

.balign 4
value: .word 0x6c617669

.text

.global main
main:
    push {lr}                        /* save lr value on stack */

    ldr r0, address_of_value         /* r0 = &value */
    ldr r0, [r0]                     /* r0 = *r0 = value */

    pop {lr}                         /* load lr (R14) register from stack */
    bx lr                            /* return from main using lr */

address_of_value: .word value

The R0 register contains the 32bit value as you can see debugging this code:

(gdb) start
Temporary breakpoint 1 at 0x103ec
Starting program: /home/pi/asm/kk

Temporary breakpoint 1, 0x000103ec in main ()
(gdb) disassemble
Dump of assembler code for function main:
   0x000103e8 <+0>:     push    {lr}            ; (str lr, [sp, #-4]!)
=> 0x000103ec <+4>:     ldr     r0, [pc, #8]    ; 0x103fc <address_of_value>
   0x000103f0 <+8>:     ldr     r0, [r0]
   0x000103f4 <+12>:    pop     {lr}            ; (ldr lr, [sp], #4)
   0x000103f8 <+16>:    bx      lr
End of assembler dump.
(gdb) info registers r0
r0             0x1      1
(gdb) stepi
0x000103f0 in main ()
(gdb) stepi
0x000103f4 in main ()
(gdb) disassemble
Dump of assembler code for function main:
   0x000103e8 <+0>:     push    {lr}            ; (str lr, [sp, #-4]!)
   0x000103ec <+4>:     ldr     r0, [pc, #8]    ; 0x103fc <address_of_value>
   0x000103f0 <+8>:     ldr     r0, [r0]
=> 0x000103f4 <+12>:    pop     {lr}            ; (ldr lr, [sp], #4)
   0x000103f8 <+16>:    bx      lr
End of assembler dump.
(gdb) info registers r0
r0             0x6c617669       1818326633

Regards.

omotto
  • 1,721
  • 19
  • 20