assemblyarm64

Why is my variable being reset to zero in ARM assembly?


I am playing around with ARM assembly on a 64bit install of Raspbian on a Pi3-B+. The code determines if a value is a prime or not.

1   
2   .data
3   testvalue: 
4       .word 0             // The number we are going to test
5   factor: 
6       .word 0         // The number we are going to test as a factor
7   limit: 
8       .word 0         // The top of the loop. testvalue - 1
9   isPrimeMsg: 
10      .asciz "%d is a prime number.\n"
11  isNotPrimeMsg: 
12      .asciz "%d is not a prime number.\n"
13  scanpattern: 
14      .asciz "%d"
15  prompt: 
16      .asciz "Input a test value: "
17  tooSmallMsg: 
18      .asciz "%d is too small.  Value must be > 5.\n"
19  diagnostic:
20      .asciz "%d, %d, %d.\n"
21
    22  .text
23  .global main
24  
25  main:
26      LDR X0, =prompt     // Load X0 with the input prompt
27      BL printf           // Print the input prompt 
28  
29      LDR X0, =scanpattern    // Load X0 with the scan pattern
30      LDR X1, =testvalue      // Load X1 with the address to store the user input
31      BL scanf            // get the user input and store it at testvalue address
32  
33      LDR X0, =testvalue      // Load X0 with the address of testvalue
34      LDR X0, [X0]            // Load X0 with the actual test value, currently 0
35      MOV X1, #5          // Load 5 into X1
36      CMP X0, X1          // Perform X0 - X1
37      BMI toosmall            // If the result is negative then test value < 5.  Jump to inform user
38  
39      LDR X0, =testvalue      // Load X1 with the address of the test value
40      LDR X0, [X0]            // Load X1 with actual test value
41      SUB X0, X0, #1      // Subtract 1 from testvalue
42      LDR X1, =limit
43      STR X0, [X1]            // Store the result in address of upper limit
44  
45      LDR X0, =factor     // Load X0 with the address of factor
46      MOV X1, #2          // Load X1 with the immediate value 2
47      STR X1, [X0]            // Store 2 at the address of factor
48  
49      LDR X0, =diagnostic     // Load X0 with diagnostic string
50      LDR X1, =testvalue      // Load X1 with address of testvalue
51      LDR X1, [X1]            // Load X1 with value of testvalue
52      LDR X2, =limit      // Load X2 with address of limit
53      LDR X2, [X2]            // Load X2 with value of limit
54      LDR X3, =factor     // Load X3 with address of factor
55      LDR X3, [X3]            // Load X3 with value of factor
56      BL printf           // Print diagnostic string
57  
58  
59  checkfactor:
60      LDR X0, =testvalue      // Load X0 with address of testvalue
61      LDR X0, [X0]            // Load X0 with the test value
62      LDR X1, =factor     // Load X1 with address of factor
63      LDR X1, [X1]            // Load X1 with the current factor candidate
64      LDR X2, =limit      // Load X2 with address of limit
65      LDR X2, [X2]            // Load X2 with the value for upper limit
66      CMP X2, X1          // Check if the factor value has reached the upper limit
67      BEQ isPrime         // If it has and we have not failed yet then we have a prime number
68  
69  subtractloop:
70      CMP X0, #0          // Compare the current testvalue with zero
71      BEQ notPrime        // If it is then we have a factor and the test value is not prime
72      BMI nextfactor      // If it's gone negative then it's time to test the next factor
73      SUB X0, X0, X1      // Otherwise keep doing division by subraction
74  
75  nextfactor:
76      LDR X0, =factor     // Load X0 with addresss of factor
77      LDR X1, [X0]            // Load X0 with value of factor
78      ADD X1, X1, #1      // Increment the value of factor by 1
79      STR X1, [X0]            // Store new value of factor in address of factor
80      B checkfactor           // Jump back and start testing again
81  
82  toosmall:
83      LDR X0, =tooSmallMsg
84      LDR X1, = testvalue
85      LDR X1, [X1]
86      BL printf
87      B end
88  
89  notPrime:
90      LDR X0, =isNotPrimeMsg
91      LDR X1, =testvalue
92      LDR X1, [X1]
93      BL printf
94      B end
95  
96  isPrime:
97      LDR X0, =isPrimeMsg
98      LDR X1, =testvalue
99      LDR X1, [X1]
100     BL printf
101     B end
102 
103 end:
104     B exit

The problem occurs between lines 39 and 49. Specifically when line 47 is executed. The output of GDB looks like:

39      LDR X0, =testvalue      // Load X1 with the address of the test value
(gdb) stepi
40      LDR X0, [X0]            // Load X1 with actual test value
(gdb) stepi
41      SUB X0, X0, #1          // Subtract 1 from testvalue
(gdb) i r x0
x0             0x13                19
(gdb) p (int)testvalue
$2 = 19
(gdb) stepi
42      LDR X1, =limit
(gdb) stepi
43      STR X0, [X1]            // Store the result in address of upper limit
(gdb) i r x0
x0             0x12                18
(gdb) p (int)limit
$3 = 0
(gdb) stepi
45      LDR X0, =factor         // Load X0 with the address of factor
(gdb) p (int)limit
$4 = 18
(gdb) stepi
46      MOV X1, #2          // Load X1 with the immediate value 2
(gdb) p (int)limit
$5 = 18
(gdb) stepi
47      STR X1, [X0]            // Store 2 at the address of factor
(gdb) i r x1
x1             0x2                 2
(gdb) p (int)limit
$6 = 18
(gdb) stepi
49      LDR X0, =diagnostic     // Load X0 with diagnostic string
(gdb) p (int)limit
$7 = 0
(gdb) p (int)testvalue
$8 = 19
(gdb) p (int)limit
$9 = 0
(gdb) p (int)factor
$10 = 2
(gdb) q

At line 42, X1 is loaded with the address for the limit variable. At line 43 the value at X0 is written to that variable address. An inspection of the value in X0 (i r x0) shows the value is 0x12 (18). If the value of limit is checked before line 43 is executed the result is 0 (p (int)limit -> $3=0). When line 43 is executed and the value at limit is checked again it's 18 (p (int)limit -> $4=18). Lines 45 and 46 are executed and when limit is checked again it's still 18 (p (int)limit -> $6=18).

When line 47 is executed (the command is STR X1, [X0]) which should store the value 2 into the variable factor, the value stored in limit is reset to zero (p (int)limit -> $7=0).

How does line 47 disturb the value at =limit when X0 has been loaded with the address for =factor?


Solution

  • .word is 32 bits but you write 64 bits to it. limit is directly after factor in memory so writing 64 bits to factor will overwrite limit with the top 32 bits which are zero. Use .quad to define 64 bit variables or switch to 32 bit registers.