Lab 6: Solutions

sum.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/**
 * sum.c
 *
 * Demonstrates how to send an int array and a double array
 * to asm files to process.
 *
 * Return the summation of the values in the array
 *     double sum_double(double[] array, int length)
 *     int sum_int(int[] array, int length)
 *
 */

#include <stdio.h>

// Prototypes
int sum_int(int *, int);
double sum_double(double *, int);

int main()
{
    // result = 210; array_size = 16
    int array_int[] = {11, 22, 33, 44, 55, 35, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

    // Determine size of the int array
    int size_array_int = sizeof(array_int) / sizeof(int);

    printf(" int values: ");

    // print array values
    for (int i = 0; i < size_array_int; i++)
    {
        printf(" %d,", array_int[i]);
    }

    int sum_i = sum_int(array_int, size_array_int);
    printf("\n size: %d; sum: %i", size_array_int, sum_i);
    printf("\n");

    //-------------------------------------
    // Double sum

    // result = 23.331000; array_size = 6
    double array_double[] = {1.111, 2.222, 3.333, 4.444, 5.555, 6.666};

    // Determine size of the double array
    int size_array_double = sizeof(array_double) / sizeof(double);

    printf(" double values: ");

    // print array values
    for (int i = 0; i < size_array_double; i++)
    {
        printf(" %lf,", array_double[i]);
    }

    double sum_d = sum_double(array_double, size_array_double);
    printf("\n size: %d; sum: %lf", size_array_double, sum_d);
    printf("\n");

    return 0;
}
sum_int.asm
; ----------------------------------------------------------------------------
; sum_int.asm
;
; NASM implementation of a function that returns the sum of all the elements
; in an int array.  The function has prototype:
;
;   int sum_int(int[], int length)
;
; arg1: A pointer to an array of integers
; arg2: A integer value containing the the length of the array.
; ----------------------------------------------------------------------------

global  sum_int

segment .data

segment .bss
    returnvalue     resd     1   ; place in memory for the return value

segment .text
sum_int:

    ; 1. Initialize stack pointers
    push    ebp             ; save caller's EBP value
    mov     ebp, esp        ; set EBP to current pointer
    ; sub   esp, N          ; reserve X=4*N bytes for N local vars
    pusha                   ; save all (including new EBP)

    ; 2. Get arg data
    mov     edx, [ebp+8]    ; address of argument (array)
    mov     ecx, [ebp+12]   ; length of array

    ; 3. Do the work!
    mov     eax, 0          ; initialize the sum and return value
    cmp     ecx, 0          ; guard against non-positive lengths
    jle     done            ; exit if length <= 0
next:
    add     eax, [edx]      ; [edx] contains the current value in the array add to eax
    add     edx, 4          ; move to next array element
                            ; 4 == sizeof(int); int data type has a size of 4.

    dec     ecx             ; count down
    jnz     next            ; if not done counting, continue
done:

    ; 4. Clean up and then exit

    mov     [returnvalue], eax      ; save return value in memory
    popa                            ; restore all (including new EBP)
    mov     eax, [returnvalue]      ; retrieve the saves return value

    mov     esp, ebp        ; remove space for local vars
    pop     ebp;            ; Return caller's EBP value

    ret                     ; return eax (aex contains the value of the stack pointer)
sum_double.asm. Double summation changes are highlighted
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
; ----------------------------------------------------------------------------
; sum_double.asm
;
; NASM implementation of a function that returns the sum of all the elements
; in a floating-point array.  The function has prototype:
;
;   double sum_double(double[], int length)
;
; arg1: A pointer to an array of floating points
; arg2: A integer value containing the the length of the array.
; ----------------------------------------------------------------------------

global  sum_double

segment .data

segment .bss
   ; returnvalue     resd     1   ; (not needed for storing the double total)

segment .text
sum_double:

    ; 1. Initialize stack pointers
    push    ebp             ; save caller's EBP value
    mov     ebp, esp        ; set EBP to current pointer
    ; sub   esp, N          ; reserve X=4*N bytes for N local vars
    pusha                   ; save all (including new EBP)

    ; 2. Get arg data
    mov     edx, [ebp+8]    ; address of argument (array)
    mov     ecx, [ebp+12]   ; length of array

    ; 3. Do the work!
    fldz                    ; initialize ST0 to 0.0
    cmp     ecx, 0          ; guard against non-positive lengths
    jle     done            ; exit if length <= 0
next:
    fadd    qword [edx]     ; ST0 += [edx]
    add     edx, 8          ; move to next array element
                            ; 8 == sizeof(double); double data type has a size of 8.

    dec     ecx             ; count down
    jnz     next            ; if not done counting, continue
done:

    ; 4. Clean up and then exit

  ; mov     [returnvalue], eax      ; (not needed for storing the double total)
    popa                            ; restore all (including new EBP)
  ; mov     eax, [returnvalue]      ; (not needed for storing the double total)
    mov     esp, ebp        ; remove space for local vars
    pop     ebp;            ; Return caller's EBP value

    ret                     ; return value already in st0
Makefile for summation project
# compiles the project files (sum.asm)
# Compiles dependencies if they are not up to date
sum: sum_int.o sum_double.o sum.o
    @echo "Building sum"
    @gcc -m32 sum.o sum_int.o sum_double.o -o sum
    ./sum

# Build sum_int.asm
sum_int.o:
    @nasm -f elf -d ELF_TYPE sum_int.asm -o sum_int.o

# Build sum_double.asm
sum_double.o:
    @nasm -f elf -d ELF_TYPE sum_double.asm -o sum_double.o

# Build sum.c
sum.o:
    @gcc -m32 -c sum.c -o sum.o

# Clean up and then rebuild all
all: clean sum

# Removes all .o and temporary files
clean:
    @echo "Cleaning up..."
    @rm -f *.o
    @rm -f sum

References: