Skip to content
Advertisement

How to add 2 numbers together that are of different lengths in x86 linux nasm assembly

I’m very new to assembly and having difficulties in getting basic calculations to work with different length numbers.

So this is my adding code, that works with numbers that are 3 or less characters long. for as long as both are the same length. for example 123 + 123 works just fine and outputs 246. But 12 + 123 does not work and it outputs 253 as the answer. How would I be able to get this working with different length numbers?

    sys_exit equ 1
    sys_read equ 3
    sys_write equ 4
    stdin equ 0
    stdout equ 1

    section .data
        newLine db 10
        cquestion db 'Enter a number: ', 0xa
        cqLen equ $ - cquestion

        answer db 'Your answer is: '
        aLen equ $ - answer


    section .bss

        number1 resb 4
        number2 resb 4
        number1Len resd 1
        number2Len resd 1

        answ resb 8

    %macro write_string 2
        mov eax, 4
        mov ebx, 1
        mov ecx, %1
        mov edx, %2
        int 0x80
    %endmacro

    section .text
    global _start
    _start:
    write_string cquestion, cqLen

    mov eax, sys_read
    mov ebx, stdin
    mov ecx, number1
    mov edx, 4
    int 0x80
    mov [number1Len], eax

    write_string cquestion, cqLen

    mov eax, sys_read
    mov ebx, stdin
    mov ecx, number2
    mov edx, 4
    int 0x80
    mov [number2Len], eax

    write_string answer, aLen

    clc
    mov ecx, [number2Len]           ;number of digits
    dec ecx                         ;need to decrease one for some reason?
    mov esi, ecx                
    dec esi                         ;pointing to the rightmost digit.
    .add_loop:

        mov al, [number1 + esi]
        adc al, [number2 + esi]
        aaa
        pushf               ; also no idea what this is here for
        or  al, 30h         ; or this
        popf                ; and this...

        mov [answ + esi], al
        dec esi
        loop addition.add_loop

        mov eax, sys_write
        mov ebx, stdout
        mov ecx, answ
        mov edx, 8
        int 0x80
        
        mov eax, sys_write
        mov ebx, stdout
        mov ecx, newLine
        mov edx, 1
        int 0x80

    mov [answ], DWORD 0

Advertisement

Answer

  • Your loop never does more than 3 iterations. If there’s a final carry, you’ll need an extra write to the destination.
  • If the code needs to deal with different length inputs, then you can’t use the same offset ESI to address corresponding digits from both numbers.
  • And neither can you use that same ESI to store the output since you could need one extra position to the left.
  • About answ resb 8, summing a couple of 3-digit numbers can at most produce a 4-digit sum.

Below is one of the many solutions to this question.

                           ECX=1
                           v
num1:  31 32 0A 00      31 32 30 30
num2:  31 32 33 0A      31 32 33 30
                              ^
                              EDX=2

answ:                   00 00 00 00     --> 30 31 33 35
                                 ^
                                 EDI=3
    mov   ecx, [number1Len]           ; Number of bytes (eg. 3)
    sub   ecx, 2                      ; Offset to 'ones' digit
    lea   eax, [ecx + 1]              ; Offset to the newline
  .more1:
    mov   byte [number1 + eax], 30h
    inc   eax
    test  eax, 3
    jnz   .more1

    mov   edx, [number2Len]           ; Number of bytes (eg. 4)
    sub   edx, 2                      ; Offset to 'ones' digit
    lea   eax, [edx + 1]              ; Offset to the newline
  .more2:
    mov   byte [number2 + eax], 30h
    inc   eax
    test  eax, 3
    jnz   .more2

    mov   edi, 3                      ; 4 iterations
    clc
  .add_loop:
    movzx eax, byte [number1 + ecx]
    adc   al, [number2 + edx]
    aaa
    lahf                              ; Preserves CF gotten from `aaa`
    or    al, 30h                     ; Convert into character "0" to "9"
    mov   [answ + edi], al
    dec   ecx
    and   ecx, 3                      ; Wraparound in number1
    dec   edx
    and   edx, 3                      ; Wraparound in number2
    sahf                              ; Restores CF
    dec   edi
    jns   .add_loop

In the result in answ we can remove at most 3 leading zeroes. If the true result is 0, the 4th character in answ would have to remain.

    mov   edx, 4
    mov   ecx, answ
  .del:
    cmp   byte [ecx], 30h
    jne   .ok
    dec   edx
    inc   ecx
    cmp   edx, 1
    ja    .del
  .ok:
    mov   ebx, stdout
    mov   eax, sys_write
    int   80h
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement