New to Assembly, trying to get a loop working

79 views Asked by At

I am just starting out with Assembly (NASM), and I try to create a variant for solving Project Euler problem 1 (add all multiples of 3 or 5 under 1000). The variant I try to make an algorithm for makes use of the fact that the multiples are spaced in a repeating pattern (+3, +2, +1, +3, +1, +2, +3 and repeat), but the loop just exits after the first iteration.

The principle should be the same as this C solution, which calculates the correct result:

int sum = 0, s = 0;
int steps[7] = {3,2,1,3,1,2,3};

for (int n = steps[s]; n < 1000; n += steps[s]) {
    sum += n;
    s++;

    if (s == 7)
        s = 0;
}

My asm looks like this:

section .data
    msg db "%d", 10, 0              ;return string for printf (just the result)
    steps dd 3, 2, 1, 3, 1, 2, 3    ;how the multiples of 3 and 5 are spaced

section .text
extern printf
global main

main:
    xor     rax, rax        ;prepare rax which will store the result
    xor     rbx, rbx        ;prepare rbx, which will be the current number

arr0:
    xor     rcx, rcx        ;prepare rcx, which will be the array index

countup:
    add     rbx, [steps + rcx * 4]  ;add steps@rcx to rbx
    add     rax, rbx                ;add rbx to the result
    inc     rcx                     ;increase the array index
    cmp     rcx, 7                  ;check if we reached the end of the array
    je      arr0                    ;if yes, jump to arr0
    cmp     rbx, 1000               ;check if we reached 1000
    jl      countup                 ;if not, loop again

... print and exit come next

The program compiles fine but the result is just 3, so obivously the loop never repeats but just executes once. What would I need to change in order to get this working?

If I manually create repeating pattern like below, it is working fine, obviously just until I reach the end of the array.

    add     rbx, [steps + rcx * 4]  ;add steps@rcx to rbx
    add     rax, rbx                ;add rbx to the result
    inc     rcx                     ;increase the array index
    add     rbx, [steps + rcx * 4]  ;add steps@rcx to rbx
    add     rax, rbx                ;add rbx to the result
    inc     rcx                     ;increase the array index
    add     rbx, [steps + rcx * 4]  ;add steps@rcx to rbx
    add     rax, rbx                ;add rbx to the result
    inc     rcx                     ;increase the array index
...
1

There are 1 answers

0
mattg On

So thanks to your comments I was able to solve the problem. As was pointed out by Erik, the main issue was the 32/64bits mixup. As soon as I either changed everything to only use the eXX registers, or adjusted the data type of the array to dq and the multiplier for the index to 8, it worked perfectly fine.

And ecm was also right of course, so I adjusted the checks and the structure a bit:

section .data
    msg db "%d", 10, 0              ;return string for printf (just the result)
    steps dd 3, 2, 1, 3, 1, 2, 3    ;how the multiples of 3 and 5 are spaced

section .text
extern printf
global main

main:
    xor     eax, eax        ;result
    xor     ebx, ebx        ;current number
    xor     ecx, ecx        ;array index

arr0:
    cmp     ecx, 7          ;check if we reached the end of the array
    jl      countup         ;if not, continue counting
    xor     ecx, ecx        ;else reset counter

countup:
    add     eax, ebx                ;add current number to result
    add     ebx, [steps + ecx * 4]  ;add steps@ecx to current number
    inc     ecx                     ;increase the array index 
    cmp     ebx, 1000               ;check if we reached 1000
    jl      arr0                    ;if not, continue