So we will now write the following very simple program in ARM assembler:
int a = 4; // a,b,c are all int typed variables int b = 5; int c; main( ) { c = a + b; } |
Read that page if you don't follow what I will do next.
.data a: .4byte 4 // a contains the value 4 b: .4byte 5 // b contains the value 5 c: .skip 4 // c is not initialized (will contain 0) |
c = a + b; |
is writting in the .text section of the assembler program.
The meaning of the statement c = a + b is:
1. Compute the value in the expression in the RHS of the assignment 2. Store the result value in memory at the address of the variable given in the LHS |
In the assignment c = a + b, we must do these actions:
|
From what you have learned in ARM assembler programming, the following ARM instructions will perform the stated tasks above:
// Move a into r1 movw r0, #:lower16:a // Moves the address of memory movt r0, #:upper16:a // variable a into register r0 ldr r1,[r0] // Move int value from var into r1 // Move b into r2 movw r0, #:lower16:b // Moves the address of memory movt r0, #:upper16:b // variable b into register r0 ldr r2,[r0] // Move int value from var into r2 // Add them up add r2, r1, r2 // r2 = a + b // Move sum in r2 to c movw r0, #:lower16:c // Moves the address of memory movt r0, #:upper16:c // variable c into register r0 str r2,[r0] |
/* -------------------------------------------------- Define required labels for EGTAPI -------------------------------------------------- */ .global main, Stop, CodeEnd .global DataStart, DataEnd .global a, b, c /* -------------------------------------------------- Begin of the program instructions -------------------------------------------------- */ .text main: // Move a into r1 movw r0, #:lower16:a // Moves the address of memory movt r0, #:upper16:a // variable a into register r0 ldr r1,[r0] // Move int value from var into r1 // Move b into r2 movw r0, #:lower16:b // Moves the address of memory movt r0, #:upper16:b // variable b into register r0 ldr r2,[r0] // Move int value from var into r2 // Add them up add r2, r1, r2 // r2 = a + b // Move sum in r2 to c movw r0, #:lower16:c // Moves the address of memory movt r0, #:upper16:c // variable c into register r0 str r2,[r0] // Move sum in r2 to var c Stop: CodeEnd: nop /* -------------------------------------------------- Begin of the permanent program variables -------------------------------------------------- */ .data DataStart: a: .4byte 4 // int a contains the value 4 b: .4byte 5 // int b contains the value 5 c: .skip 4 // int c is not initialized (will contain 0) DataEnd: .end |
How to run the program:
|
When you write assembler programs, it is very important that:
|
Data type Load instruction Store instruction ------------- ------------------ ------------------- int ldr str short ldrsh strh byte ldrsb strb |
If you use a wrong instruction for a given data type, your program may not work correctly (because incorrect data may be copied between the CPU and the memory)
I will do 2 examples with mixed data type operations.
byte a = 4; // 3 different data types short b = 5; int c = 256; main( ) { c = a + b; } |
We need to align some variables because of alignment requirements (see: click here)
.data a: .byte 4 // a contains the value 4 in 8 bits .align 1 b: .2byte 5 // b contains the value 5 in 16 bits .align 2 c: .4byte 256 // c contains the value 256 in 32 bits |
The assembler program must use the correct load and store instructions for each variable.
Here are the changes (highlight in red):
main: // Move a into r1 movw r0, #:lower16:a // Moves the address of memory movt r0, #:upper16:a // variable a into register r0 ldrsb r1,[r0] // Move byte value from var into r1 // ldrsb also sign-extend to int for computation !! // Move b into r2 movw r0, #:lower16:b // Moves the address of memory movt r0, #:upper16:b // variable b into register r0 ldrsh r2,[r0] // Move short value from var into r2 // ldrsh also sign-extend to int for computation !! // Add them up add r2, r1, r2 // r2 = a + b // Move sum in r2 to c movw r0, #:lower16:c // Moves the address of memory movt r0, #:upper16:c // variable c into register r0 str r2,[r0] // Move sum in r2 to int var c |
How to run the program:
|
byte a = 4; // 3 different data types short b = 5; int c = 256; main( ) { a = b + c; // a is a byte typed variable !!! } |
Because the variable types have not changed, we can use the same .data segment (I won't repeat it here).
The statement has changed.
Now we must get the values from b and c, add them up and store the sum in the variable a.
When you write the assembler code, we need to make sure we use the correct load/store instruction for each data type.
The assembler program is as follows:
main: // Move short b into r1 movw r0, #:lower16:b // Moves the address of memory movt r0, #:upper16:b // variable b into register r0 ldrsh r1,[r0] // Move short value from var into r1 // ldrsb also sign-extend to int !! // Move c into r2 movw r0, #:lower16:c // Moves the address of memory movt r0, #:upper16:c // variable c into register r0 ldr r2,[r0] // Move int value from var into r2 // Add them up add r2, r1, r2 // r2 = b + c // Move sum in r2 to a movw r0, #:lower16:a // Moves the address of memory movt r0, #:upper16:a // variable a into register r0 strb r2,[r0] // Move sum in r2 to byte var c |
How to run the program:
|
Can you explan why a = 5 after the execution ???
|
Try c = 100 - you will see that there is no overflow and the program is correct
|