Product of nasm matrices

Asked

Viewed 511 times

1

I have to make an algorithm that will multiply a matrix A by a matrix B and put the result into a third matrix. The matrices are square, of same size and will be passed by reference by another program in C.

The problem is that errors only appear when I try to compile . c, while . asm is linked smoothly and I have no idea where I’m going wrong. If anyone can shed some light, I’d be grateful.

;mulMatriz_asm(int mA[][MATRIZ_SIZE], int mB[][MATRIZ_SIZE], int mRes[][MATRIZ_SIZE], int mSize)
    SECTION .text

    global mulMatriz_asm

mulMatriz_asm:
    incr equ 4

    %define offma 0     ;deslocamento mA
    %define offmb 0     ;deslocamento mB
    %define offmres 0   ;deslocamento mRes

    push ebp
    mov ebp, esp
    mov ebx, [ebp+20]

    sub eax, eax
    sub ecx, ecx
    sub edx, edx

colRes:;edx -> k 
    push eax
    push ecx
    push edx
    push ebx

    mov eax, [ebp+8];*mA
    mov eax, [eax+offma];ma[i][j]

    mov ecx, [ebp+12];*mB
    mov ecx, [ecx+offmb];mb[j][k]
    mul ecx

    mov edx, [ebp+16];*mRes
    mov ebx, [edx+offmres];mRes[i][k]
    add ebx, eax

    mov [edx+offmres], ebx;mRes += mA * mB

    mov eax, incr

    mov ebx, offmb
    add ebx, eax        ;próxima coluna de mB
    %define offmb ebx

    mov ecx, offmres
    add ecx, eax        ;próxima coluna de mRes
    %define offmres ecx

    pop ebx
    pop edx
    pop ecx
    pop eax

    inc edx
    cmp edx, ebx
    jl colRes
colA:;ecx -> j
    sub edx, edx

    push edx
    push ecx

    mov edx, incr

    mov ecx, offma
    add ecx, edx    ;próxima coluna de mA
    %define offma ecx

    mov edx, offmb
    add edx, ebx    ;próxima linha de mB
    %define offmb edx

    pop ecx
    pop edx

    inc ecx
    cmp ecx, ebx
    jl colRes
linhaA:;eax -> i
    sub ecx, ecx
    sub edx, edx

    push ecx

    mov ecx, offma
    add ecx, ebx    ;proxima linha de mA
    %define offma ecx

    mov ecx, offmres
    add ecx, ebx    ;proxima linha de mRes
    %define offmres ecx

    pop ecx

    inc eax
    cmp eax, ebx
    jl colA

    ret

1 answer

0

Follow the main problems in your code:

  • The stack frame created, is not restored before return. At the end of the function, it is necessary to restore the stack:

    ...
    mov     esp, ebp
    pop     ebp
    ret
    
  • The command %define defines a macro and is not an instruction in Assembly. For example, on the line %define offmres ecx, the value of the macro offmres will not be updated with the value stored in the register ecx (and this will cause problems in the calculation of offset of the matrix)

  • As the prototype of the C indicates that the matrix data type is int (integer with signal), the ideal is to use the instruction imul to perform multiplication (instead of mul)


Below is a commented and didactic (not optimized) example to perform matrix multiplication with nasm. You can use it as a starting point to adjust your algorithm.

This algorithm uses local variables, allocated to the stack, to store the loopings (i, j and k) and the scalar product (sum):

; mulMatriz_asm(
;   int mA[][MATRIZ_SIZE], 
;   int mB[][MATRIZ_SIZE], 
;   int mRes[][MATRIZ_SIZE], 
;   int mSize)

section .text

global _mulMatriz_asm

; --- Macros ---
; Parametros
%define mA              dword [ebp + 8]     ; matriz A
%define mB              dword [ebp + 12]    ; matriz B
%define mC              dword [ebp + 16]    ; matriz Resultado
%define mSize           dword [ebp + 20]    ; tamanho

; Variaveis locais
%define sum             dword [ebp - 4]     ; utilizada no cálculo do produto escalar
%define indice_i        dword [ebp - 8]     ; utilizado no "for (i=0..."
%define indice_j        dword [ebp - 12]    ; utilizado no "for (j=0..."
%define indice_k        dword [ebp - 16]    ; utilizado no "for (k=0..."

; --- Início ---
_mulMatriz_asm:
    push    ebp                 ; Inicializa o frame
    mov     ebp, esp
    sub     esp, $80            ; Aloca espaço para as variáveis locais...
    push    ebx                 ; ...e salva os registradores
    push    ecx
    push    edx
    push    esi
    push    edi

    mov     esi, mA             ; armazena o endereço base de mA no registrador esi
    mov     edi, mB             ; armazena o endereço base de mB no registrador edi
    mov     indice_i, $0        ; inicializa o looping "i" com zero

forI:
    mov     ecx, indice_i
    cmp     ecx, mSize          ; se (i >= mSize) então vai para "fim"
    jge     fim                             

    mov     indice_j, $0        ; inicializa o looping "j" com zero
forJ:
    mov     ecx, indice_j
    cmp     ecx, mSize          ; se (j >= mSize) então vai para "fimForI"
    jge     fimForI

    mov     sum, $0             ; inicializa a somatória do produto escalar

    mov     indice_k, $0        ; inicializa o looping "k" com zero
forK:
    mov     ecx, indice_k
    cmp     ecx, mSize          ; se (k >= mSize) então vai para "fimForJ"
    jge     fimForJ 

    mov     ebx, indice_i       ; calcula o endereço do elemento mA[i][k]
    imul    ebx, mSize                      
    add     ebx, indice_k       ; ebx = (indice_i * mSize + indice_k) 
    shl     ebx, 2              ; multiplica ebx por 4 ==> sizeof(int) para 32bits
    mov     eax, [esi + ebx]    ; carrega o elemento da matriz A em eax

    mov     ebx, indice_k       ; calcula o endereço do elemento mB[k][j] 
    imul    ebx, mSize
    add     ebx, indice_j
    shl     ebx, 2              ; ebx = (indice_k * mSize + indice_j) * 4 
    mov     ecx, [edi + ebx]    ; carrega o elemento da matriz B em ecx

    imul    eax, ecx            ; eax <- mA[i][k] * mB[k][j]
    add     sum, eax            ; acumula o resultado na variável local sum

fimForK:
    inc     indice_k            ; incrementa o looping "k"
    jmp     forK

fimForJ:
    mov     ebx, indice_i       ; calcula o endereço do elemento mRes[i][j]
    imul    ebx, mSize
    add     ebx, indice_j
    shl     ebx, 2              ; ebx = (indice_i * mSize + indice_j) * 4 
    mov     eax, sum            ; carrega a somatória em eax
    mov     ecx, mC             ; carrega o endereço base de mRes em ecx
    mov     [ecx + ebx], eax    ; armazena o resultado da somatória em mRes[i][j]

    inc     indice_j            ; incrementa o looping "j"
    jmp     forJ    

fimForI:
    inc     indice_i            ; incrementa o looping "i"
    jmp     forI    

fim:
    pop     edi                 ; restaura os registradores salvos
    pop     esi
    pop     edx
    pop     ecx
    pop     ebx
    mov     esp, ebp            ; restaura o frame
    pop     ebp
    ret                         ; retorna

tested with NASM version 2.12.02 compiled on Jul 6 2016

Browser other questions tagged

You are not signed in. Login or sign up in order to post.