For some reason, when I try to compile this bit of code, the compiler says syscall.s:72:invalid constant (0x172) after fixup
:
.globl _mach_msg_trap$MACH
_mach_msg_trap$MACH:
stmfd sp!, {r4,r7}
mov r7, #370 /* this is line 72 */
svc 0
ldmfd sp!, {r4, r7}
bx lr
I don't know why it's doing it. When I put a smaller constant into r7
, it works fine. But with higher numbers, it spits out this error. I've temporary fixed it by doing mov r7, #300
and add r7, #70
, which achieves the desired effect. Still not sure what caused the error though.
The ARM Instruction Set, up to ARMv5, is only able to use a limited range of immediate values. The problem is that the value has to be encoded in the instruction itself. As all ARM Instructions are 32-bit wide, the original instruction-set up to ARMv5 only had a total of 8+4 bits to encode immediates. With the first 8-bit being able to load any 8-bit value in the range of 0-255 and the 4 bit being a right rotate in steps of 2 between 0 and 30.
So you can load values like:
#0
#122
#121 ror #24 = 30976
#230 ror #12 = 241172480
But, #370 is not loadable with this scheme, it would require something like #185 ror #31
which is not possible.
There are two ways to get your immediate value loaded.
ldr r7,=#370
The assembler then will create a constant-pool and load the value from there via pc-relative addressing.Usually you should prefer to construct constants with up to 2 instructions, if thats not possible (or the value has to be relocatable) use ldr.
Starting with ARMv7 you can also use movw
to load any 16 bit value in the lower half of a register while zeroing the top-half and movt
to load another 16bit value to the upper half without touching the lower half.