Search code examples
assemblyx86attsign-extension

How to sum integers with sign into a wider sum on IA32. 64-bit sum of 32-bit signed ints?


I'm trying to sum a list of integers with sign on Assembly 32 but i have only got to sum integers without sign. Do you know some way to do it?

My program tries to sum integers and store in resultado, whose size is 64 bits, so to be able to do that I use two registers of 32 bits(EAX and EDX), and I check when the sum produces carry.

After of all that, I join EAX and EDX on resultado.

# sum.s     Sumar los elementos de una lista.
#           llamando a función, pasando argumentos mediante registros
# retorna:  código retorno 0, comprobar suma en %eax mediante gdb/ddd.
# as --32 -g sum.s -o sum.o
# ld -m elf_i386 sum.o -o sum

# DATA SECTION
.section .data
lista:
    .int 4294967295, 4294967295, 4294967295, 4294967295

longlista:
    .int (.-lista)/4
resultado:
    .quad -1


.section .text
_start: .global _start

    mov $lista, %ebx
    mov longlista, %ecx
    call suma
    mov %eax, resultado
    mov %edx, resultado+4

    mov $1, %eax
    mov $0, %ebx
    int $0x80


suma:
    push %esi
    mov $0, %eax
    mov $0, %edx
    mov $0, %esi

bucle:
    add (%ebx,%esi,4), %eax
    jc .L1

bucle1:
    inc %esi
    cmp %esi,%ecx
    jne bucle
    pop %esi
    ret

.L1:
    inc %edx
    jmp bucle1

This gives a 64-bit sum that treats the inputs as unsigned 32-bit, which isn't what I want.


Solution

  • Next code that uses 64-bit addition will give a correct sum for positive and negative numbers alike without any wraparound due to only using 32 bit registers.
    The signed result can exceed the range [-2GB,+2GB-1].

    suma:
        push %esi
        push %edi
        xor  %esi, %esi           ;Clear %edi:%esi
        xor  %edi, %edi
        sub  $1, %ecx             ;Start at last element in array
        jl   emptyArray
    bucle:
        mov  (%ebx,%ecx,4), %eax  ;From signed 32-bit to signed 64-bit
        cdq
        add  %eax, %esi           ;Add signed 64-bit numbers
        adc  %edx, %edi
        dec  %ecx
        jge  bucle
    emptyArray:
        mov  %esi, %eax           ;Move result from %edi:%esi to %edx:%eax
        mov  %edi, %edx
        pop  %edi
        pop  %esi
        ret
    

    The order in which the additions are made is unimportant, and so the code starts with the last element working towards the first one.