添加矩阵的汇编例程没有给出预期的输出

Assembly routine to add matrices not giving expected output

我正在编写一个将两个二维矩阵相加的汇编例程。代码是用 MASM 语法编写的。

; --------------------
; matrixAdd.asm
; --------------------

; Adds two matrices

; extern "C" int matrixAdd(int *matrixOnePtr, int *matrixTwoPtr, long long rows, long long cols)

    .code
matrixAdd proc frame
    ; function prologue
    push r12                                                    ; push r12 register for use
    .pushreg r12
    push r13                                                    ; push r13 register for use
    .pushreg r13
    push r14                                                    ; push r14 register for use
    .pushreg r14
    .endprolog
    
    ; validate number of rows and columns
    cmp r8, 0                                                   ; compare rows 
    jle InvalidArg                                              ; jump to InvalidArg if rows <= 0
                                        
    cmp r9, 0                                                   ; compare cols
    jle InvalidArg                                              ; jump to InvalidArg if cols <= 0

    xor r10, r10                                                ; set r10 (increment variable) to 0

LoopOne:
    xor r11, r11                                                ; set r11 (inner increment variable) to 0

LoopTwo:
    mov r12, rcx                                                ; move first pointer to r12
    mov r13, rdx                                                ; move second pointer to r13

    ; calculate offset
    mov r14, r10                                                ; move r10 (outer increment variable) to r14
    imul r14, r9                                                ; multiply r14 by number of columns
    add r14, r11                                                ; add inner increment variable
    imul r14, 4                                                 ; multiply offset by 4

    add r12, r14                                                ; add offset to first pointer
    add r13, r14                                                ; add offset to second pointer

    mov r14, [r13]                                              ; move value of second pointer to r14
    add [r12], r14                                              ; add two matrices

    inc r11                                                     ; increment inner increment variable
    cmp r11, r9                                                 ; compare inner increment variable to columns
    jle LoopTwo                                                 ; jump if r11 <= cols

    ; LoopOne; check if outer increment variable is <= rows
    inc r10                                                     ; increment outer increment variable
    cmp r10, r8                                                 ; compare r10 to rows
    jle LoopOne                                                 ; jump if r10 <= rows

    pop r12                                                     ; restore r12 register
    pop r13                                                     ; restore r13 register
    pop r14                                                     ; restore r14 register
    xor eax, eax                                                ; set successful return code
    ret                                                         ; return 0

; Rows or columns is invalid
InvalidArg:
    pop r12                                                     ; restore r12 register
    pop r13                                                     ; restore r13 register
    pop r14                                                     ; restore r14 register
    mov eax, 1                                                  ; move 1 into eax register
    ret                                                         ; return 1
matrixAdd endp  
    end

主要功能如下:

#include <stdio.h>

extern int matrixAdd(int *matrixOnePtr, int *matrixTwoPtr, long long rows, long long cols);

int main(int argc, char **argv) {
    int a1[3][3] = {
        {1, 2, 3},
        {1, 2, 3},
        {1, 2, 3}
    };

    int a2[3][3] = {
        {1, 2, 3},
        {1, 2, 3},
        {1, 2, 3}
    };

    matrixAdd(a1, a2, 3, 3);

    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            printf("%d ", a1[i][j]);
        }

        printf("\n");
    }
}

预期的输出应该是

2 4 6
2 4 6
2 4 6

但是结果是

2 6 9
4 8 9
4 8 9

我一直在尝试调试代码,但它不起作用。我的电脑是 Windows 10 64 位。每个矩阵都是 3x3。我是 x86 汇编编程的新手。

  • 你的(汇编语言)算法从根本上是低劣的。 显然,您只是在翻译两个嵌套循环(因为它在 HLL 中是习惯的和正确的)。 但是,您忘记了一个事实,即 int[6][7] 在内存方面等同于 int[42]。 考虑到您要执行矩阵 加法 ,一系列 rows * cols 求和更有效。
  • 另外,这将简化地址计算。 对于(纯)地址计算,顺便说一下,您通常使用 lea 指令。 别担心,作为一个新手,它可能是一个令人生畏的复杂指令,对我来说也是如此。
  • 您正在 循环中加载“first/second 指向 r12/r13 的指针”。 这是错误的(或者至少是不必要的,因为你没有覆盖 rcx/rdx)。 你应该只做一次,我。 e.在循环外。
  • 正如 已经评论的那样: 由于数组的 zero-based 索引,中止条件不应包括 =。 例如,在 int[3] 的情况下,您想遍历集合 {0, 1, 2}.
  • 此外 已经评论过,这是主要问题mov r14, [r13]add [r12], r14 将检索 64 位 数量并对其进行操作。 mov 中目标寄存器的大小很重要。 mov r14d, [r13] 将检索一个“双字”,i。 e.一个 32 位的数量。 同样,add dword ptr [r12], r14d 将添加两个 32 位值。 请注意,内存地址(在 64 位系统上)始终需要指定为 full 64 位寄存器。 dword ptr 前缀将告知 MASM 内存操作数大小,因此它的汇编方式不同。
  • a1[0][0]中的结果实际上是正确的,因为x86架构是一个小端系统。
  • 您在例程(两个可能的)末端的 pop 指令必须采用 reverse push 顺序。 您的代码实际上是在调用站点上下文中交换 r12r14 的内容。 理想情况下,您会合并两个函数结尾,但一次解决一个问题。
  • 最后,您的函数 返回一个 (non-constant) int 值,但您的 C 代码没有检查它。 声明您的函数 void 可能是最简单的解决方案。