Online Compiler Nasm

section .data fmt_3: db "%d %d %d", 0 fmt_i: db "%d", 0 fmt_sp: db " ", 0 fmt_nl: db 10, 0 section .bss N: resd 1 M: resd 1 K: resd 1 limit: resd 1 ; Лимит для цикла чтения (N*M + M*K) ptr_B: resd 1 ; Базовый адрес начала матрицы B в байтах ptr_C: resd 1 ; Базовый адрес начала матрицы C в байтах arr: resd 30015 ; Единый массив для A, B и C section .text global main extern scanf, printf main: push ebp mov ebp, esp push ebx push esi push edi ; 1. Читаем N, M, K push K push M push N push fmt_3 call scanf add esp, 16 ; Вычисляем смещения матриц и лимит чтения mov eax, [N] imul eax, [M] ; EAX = N * M (размер A) lea ebx, [arr + eax*4] mov [ptr_B], ebx ; ptr_B = адрес начала B mov ecx, [M] imul ecx, [K] ; ECX = M * K (размер B) lea edx, [ebx + ecx*4] mov [ptr_C], edx ; ptr_C = адрес начала C add ecx, eax mov [limit], ecx ; limit = N*M + M*K ; 2. Считываем матрицы A и B в одном цикле xor esi, esi ; esi = текущий индекс элемента .read_loop: cmp esi, [limit] ; Безопасно проверяем лимит из памяти jge .mult_prep lea eax, [arr + esi*4] push eax push fmt_i call scanf add esp, 8 inc esi jmp .read_loop ; 3. Умножение матриц C = A * B ; Роли регистров: ESI = i, EDI = j, EBX = l .mult_prep: xor esi, esi ; i = 0 .loop_i: cmp esi, [N] jge .print_prep xor edi, edi ; j = 0 .loop_j: cmp edi, [K] jge .next_i xor ecx, ecx ; ECX = sum = 0 (аккумулятор) xor ebx, ebx ; l = 0 .loop_l: cmp ebx, [M] jge .store_C ; Матрица A[i][l] -> индекс = i * M + l mov eax, esi imul eax, [M] add eax, ebx mov edx, [arr + eax*4] ; edx = A[i][l] ; Матрица B[l][j] -> индекс = l * K + j mov eax, ebx imul eax, [K] add eax, edi ; теперь eax = l * K + j ; Берем базу ptr_B из памяти, не трогая EDI push ecx ; временно сохраняем промежуточную сумму mov ecx, [ptr_B] mov eax, [ecx + eax*4] ; eax = B[l][j] imul eax, edx ; eax = A[i][l] * B[l][j] pop ecx ; восстанавливаем сумму add ecx, eax ; sum += eax inc ebx ; l++ jmp .loop_l .store_C: ; Матрица C[i][j] -> индекс = i * K + j mov eax, esi imul eax, [K] add eax, edi mov edx, [ptr_C] mov [edx + eax*4], ecx ; Сохраняем итоговую sum в C[i][j] inc edi ; j++ jmp .loop_j .next_i: inc esi ; i++ jmp .loop_i ; 4. Вывод матрицы C .print_prep: xor esi, esi ; i = 0 .print_i: cmp esi, [N] jge .exit xor edi, edi ; j = 0 .print_j: cmp edi, [K] jge .print_nl ; Индекс элемента C[i][j] mov eax, esi imul eax, [K] add eax, edi mov edx, [ptr_C] push dword [edx + eax*4] push fmt_i call printf add esp, 8 push fmt_sp call printf add esp, 4 inc edi jmp .print_j .print_nl: push fmt_nl call printf add esp, 4 inc esi jmp .print_i .exit: pop edi pop esi pop ebx mov esp, ebp pop ebp xor eax, eax ret
This code reads three dimensions N, M, K, then reads the elements of matrix A (size N×M) and matrix B (size M×K) into a single flat array. It then performs matrix multiplication to compute C = A × B (size N×K) and prints the result. The matrices are stored contiguously in memory: first A, then B, then space for C.

- In the multiplication loop, when computing B[l][j], you load the base address `ptr_B` from memory but then overwrite `eax` with the offset calculation before using it. Check the order of operations: you compute the offset into `eax`, then load `ptr_B` into `ecx`, but by that time `eax` has already been changed. You need to preserve the offset or compute it after loading the base address.

- The `push ecx` / `pop ecx` around the B access is unnecessary and may cause confusion. The accumulator `ecx` is not modified by the `mov` and `imul` instructions that follow, so you can remove those push/pop and simplify the code.