Estou brincando com ARM Assembly em uma instalação de 64 bits do Raspbian em um Pi3-B +. O código determina se um valor é primo ou não.
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
O problema ocorre entre as linhas 39 e 49. Especificamente quando a linha 47 é executada. A saída do GDB é semelhante a:
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
Na linha 42, X1 é carregado com o endereço da variável limite. Na linha 43 o valor em X0 é escrito nesse endereço de variável. Uma inspeção do valor em X0 (ir x0) mostra que o valor é 0x12 (18). Se o valor do limite for verificado antes da linha 43 ser executada, o resultado será 0 (p (int)limit -> $3=0). Quando a linha 43 é executada e o valor no limite é verificado novamente, é 18 (p (int)limit -> $4=18). As linhas 45 e 46 são executadas e quando o limite é verificado novamente ainda é 18 (p (int)limit -> $6=18).
Quando a linha 47 é executada (o comando é STR X1, [X0]) que deve armazenar o valor 2 na variável factor, o valor armazenado em limit é zerado (p (int)limit -> $7=0).
Como a linha 47 perturba o valor em =limit quando X0 foi carregado com o endereço para =factor?
.word
é de 32 bits, mas você escreve 64 bits nele.limit
está diretamente apósfactor
a memória, portanto, gravar 64 bitsfactor
será sobrescritolimit
pelos 32 bits superiores, que são zero. Use.quad
para definir variáveis de 64 bits ou mudar para registros de 32 bits.