; *********************************************************************** ; * * ; * Load Constant Values into Registers * ; * * ; *********************************************************************** ; Author: John Zaitseff ; Date: 9th September, 2002 ; Version: 1.3 ; This program shows how constant values may be loaded into registers. ; Its primary purpose is to illustrate the different formats that the GNU ; Assembler accepts for numbers and expressions. It also shows how to use ; the "ldr =" pseudo-instruction for arbitrary constants. .text .global _start _start: ; Stage 1: Illustrate different number formats for loading values stg1: mov r0,#84 ; R0 := 84; operand is in decimal mov r1,#0x4E ; R1 := 78; operand is in hexadecimal mov r2,#0347 ; R2 := 231; operand is in octal mov r3,#0b11001101 ; R3 := 205; operand is in binary mov r4,#'Z' ; R4 := 90; operand is a character ; Stage 2: Some simple numeric expressions stg2: mov r0,#7*9+2 ; R0 := 65 as a numeric expression mov r1,#(7 * 9) + 2 ; Slightly more readable mov r2,#((7 * 9) + 2) ; Even more readable .set value, (7 * 9) + 2 ; Define the symbol "value" mov r3,#value ; and use that instead of an in-line expression ; In general, you should always use an appropriately-named symbol instead ; of using in-line "magic numbers". This makes your program much more ; readable. Of course, use your common sense, too! ; Stage 3: Load immediate constants stg3: ; The immediate operand has a limited range; not every 32-bit constant can ; be specified directly. A valid immediate operand satisfies the ; following equation: ; n = i ROR (2 * r) ; where n is the immediate operand, i is a number between 0 and 255 ; (inclusive), r is between 0 and 15 (inclusive) and ROR is the rotate ; right operation. ; ; See page A5-6 of the ARM Architecture Reference Manual (page 222 of the ; PDF document) for more information. mov r1,#0xFF ; i = 255, r = 0 mov r2,#0x100 ; i = 1, r = 12 mov r3,#0x400 ; i = 1, r = 11 mov r3,#0x1000 ; i = 1, r = 10 mov r2,#0xFF000000 ; i = 255, r = 4 ; Try replacing one or more of the above constants with your own. Is the ; constant 257 (0x101) allowable, for example? What about 258 (0x102)? ; What is the next valid constant after 0x100? And the one after that? ; Stage 4: Substitution of instructions stg4: mov r0,#-1 ; -> mvn r0,#0 (-1 is 0xFFFFFFFF) mov r1,#0xFFFFFFFF ; -> mvn r0,#0 mov r2,#-6 ; -> mvn r0,#5 (NOT 5 = 0xFFFFFFFA = -6) mvn r3,#-6 ; -> mov r0,#5 (NOT 0xFFFFFFFA = 5, not 6) add r0,r0,#-6 ; -> sub r0,r0,#6 ; If the GNU Assembler cannot directly use a given constant, it tries to ; use a single alternative instruction to do the job. It is only when a ; constant cannot fit into its instruction OR into its alternative that it ; reports an error. ; You can verify the substitutions by disassembling the executable. To do ; this, type the following command lines: ; make values.elf ; arm-elf-objdump -d values.elf | more ; Stage 5: Arbitrary constants and the literal pool stg5: ; mov r0,#0x43D ; Invalid constant ; Try removing the comment character ";" from the start of the previous ; line and recompiling. You should end up with an error message: the ; constant does not meet the restrictions of immediate constants. ; One way of loading this constant is with two or more instructions, ; although this is very tedious: stg5a: mov r0,#0x400 ; R0 := 0x400 add r0,r0,#0x3D ; R0 := 0x400 + 0x3D = 0x43D ; Another way is by loading the constant from memory: stg5b: ldr r0,[pc,#0] ; R0 := word stored in memory b stg5c ; Skip over the stored constant .word 0x43D ; The word stored in memory ; The best way to load arbitrary constants is with the "ldr =" pseudo- ; instruction. stg5c: ldr r0,=1 ; -> mov r0,#1 ldr r1,=-1 ; -> mvn r1,#0 ldr r2,=0xFF000000 ; -> mov r2,#0xFF000000 ldr r3,=0x43D ; -> ldr r3,[pc,#12] ldr r4,=value * 123 ; -> ldr r4,[pc,#12] ldr r5,=1234567890 ; -> ldr r5,[pc,#12] ldr r6,=123 * value ; -> ldr r6,[pc,#4] - constant is reused exit: swi 0x11 ; Terminate the program ; The "ldr =" pseudo-instruction is always replaced by a single real ; instruction. If the constant cannot be loaded with "mov" or "mvn", a ; real "ldr" is used instead, using the same strategy as in stg5b. The ; constants are stored either at the point of a ".ltorg" directive or at ; the end of the .text section: .ltorg ; Place assembler-generated constants here ; The constants used in this program are: ; .word 0x43D ; .word value * 123 ; 0x1F3B (used twice) ; .word 1234567890 ; 0x499602D2 ; You can verify that these constants are present by disassembling the ; executable. They can be found following the "swi 0x00000011" and will ; appear as "garbage" instructions. .end