The C/C++ assignment operator, β=β, causes the expression on the right-hand side of the operator to be evaluated and the result to be associated with the variable that is named on the left-hand side. Subsequent uses of the variable name in the program will evaluate to this same value. For example,
will assign the integer to the variable x. If x is later used in an expression, the value assigned to x will be used in evaluating the expression. For example, the expression
causes a location to be allocated and that location to be given the name βx.β That is, other parts of the program can refer to the location where the value of x is stored by using the name βx.β
The type name in the declaration, int, tells the compiler how many bytes to allocate and the code used to represent the data stored at this location. The int type uses the two's complement code. So the assignment statement,
The program in Listing 11.2.1 uses the assignment operator to store values in the x, y, and z variables. We use the register type modifier to βadviseβ the compiler to use a register for the x and y variables.
/* assignment1.c
* Assign a 32-bit pattern to a register
*
* 2017-09-29: Bob Plantz
*/
#include <stdio.h>
int main(void)
{
register int x, y;
int z;
x = 123;
y = 4567;
z = x + y;
printf("%i + %i = %i\n", x, y, z);
return 0;
}
Listing 11.2.3 shows my assembly language solution. It is essentially the same as what the compiler generated, but I have used names for labels and constants that will help with the explanation of the code.
@ assignment2.s
@ Assignment three ways.
@ 2017-09-29: Bob Plantz
@ Define my Raspberry Pi
.cpu cortex-a53
.fpu neon-fp-armv8
.syntax unified @ modern syntax
@ Useful source code constants
.equ z,-16
.equ local,8
@ Constant program data
.section .rodata
.align 2
formatMsg:
.asciz "%i + %i = %i\n"
@ Program code
.text
.align 2
.global main
.type main, %function
main:
sub sp, sp, 12 @ space for saving regs
str fp, [sp, 0] @ save fp
str lr, [sp, 4] @ lr
str r5, [sp, 8] @ r5
str r4, [sp, 12] @ and r4
add fp, sp, 12 @ our frame pointer
sub sp, sp, local @ allocate memory for local var
mov r5, 123 @ x = 123;
ldr r4, yValue @ y = 4567;
add r3, r5, r4 @ x + y
str r3, [fp, z] @ z = x + y;
ldr r0, formatMsgAddr @ printf("%i + %i = %i\n",
mov r1, r5 @ x,
mov r2, r4 @ y,
ldr r3, [fp, z] @ z);
bl printf
mov r0, 0 @ return 0;
add sp, sp, local @ deallocate local var
ldr fp, [sp, 0] @ restore fp
ldr lr, [sp, 4] @ lr
ldr r5, [sp, 8] @ r5
ldr r4, [sp, 12] @ r4
add sp, sp, 12 @ and sp
bx lr @ return
.align 2
yValue:
.word 4567
formatMsgAddr:
.word formatMsg
where the value of local was computed to (a) allow enough memory space for the int variable, and (b) make sure the stack pointer is always on an eight-byte addressing boundary, as required by the protocol when calling a public function (printf in this case).
in Listing 10.1.4. The integer value, , is within the range that can be moved directly into a register. However, cannot, so it is stored in memory and loaded into a register from memory.
The compiler honored our request to use registers for both the x and y variables. However, the z variable is allocated in the stack frame. So after the addition is performed, the sum is stored in memory at a location relative to the frame pointer:
Recall from Section 9.2 that [fp, z] specifies the address obtained by adding the value of z to the value contained in the fp register. In this function z is an offset of bytes from the address in fp.
In Section 11.3 we discuss the machine code for the instructions that implement these assignment statements. In particular, we will be looking at how the location of each variable is encoded in the machine language.