组合函数转置矩阵中的指针问题

Problems with pointers in asembly function transposing matrix

提问人:szyjas 提问时间:10/28/2023 最后编辑:Sep Rolandszyjas 更新时间:11/4/2023 访问量:105

问:

在我的代码中,我尝试使用在汇编中编写的函数转置动态矩阵 (IN64) 似乎我试图从矩阵外部读取,或者我在试图指出我的函数应该从哪里移动并保存字节时犯了一个错误。

请帮助我解决这个问题,因为正确理解我犯了什么错误对我来说很重要

下面是使用函数转置的 c++ 代码

#include <iostream>
#include <windows.h>

extern "C" void transpose(INT64**, INT64);

// Function for displaying the matrix
void printMatrix(INT64** matrix, INT64 n) {
    for (INT64 i = 0; i < n; ++i) {
        for (INT64 j = 0; j < n; ++j) {
            std::cout << matrix[i][j] << " ";
        }
        std::cout << std::endl;
    }
}

int main() {
    INT64 n = 8; // Matrix size

    // Initialization of matrix A
    INT64** A = new INT64 * [n];
    for (INT64 i = 0; i < n; ++i) {
        A[i] = new INT64[n];
        for (INT64 j = 0; j < n; ++j) {
            A[i][j] = i * n + j; // Filling matrix A
        }
    }

    std::cout << "Matrix before transposition:" << std::endl;
    printMatrix(A, n); // Display the matrix before transposition

    // Calling the transpose function
    transpose(A, n);

    std::cout << "Matrix after transposition:" << std::endl;
    printMatrix(A, n); // Display the matrix after transposition

    // Deallocate memory
    for (INT64 i = 0; i < n; ++i) {
        delete[] A[i];
    }
    delete[] A;

    return 0;
}

和 heres 转置函数

.code


transpose PROC
    mov r10, rax ; Store the dimension 8 in r10
    mov r11, rax ; Store the dimension 8 in r11

loopRow:
    mov r8, [rcx + rax]      ; Initialize the row index (i) to 8 (8,7,6,5,4,3,2,1)
    mov r9, [rcx + 8 * rax]      ; Initialize the column index (j) to 8 (56,48,40,32,24,16,8,0)

loopColumn:
    mov rdx, [r9 + rdi * 8] ; Load the element from the matrix (56,48,40,32,24,16,8,0)
    mov rsi, [rcx + rdi * 8] ; Load the element from the matrix (7,6,5,4,3,2,1,0)
    mov [r9 + rdi * 8], rsi ; Assign the element to the transposed location
    mov [rcx + rdi * 8], rdx
    inc rdi        ; Move to the next column
    cmp rdi, r10   ; Check if all columns are finished
    jl loopColumn
    inc r11        ; Move to the next row
    cmp rdi, r11   ; Check if all rows are finished
    jl loopRow

    ret
transpose ENDP

END

我试图以多种方式修复该代码感到失败,但似乎我只是在我的功能不起作用时错过了一些重要的东西

[编辑]

这是我尝试解决它的下一个代码:

.code

transpose PROC
    mov r10, rdx ; matrix size n
    mov r11, rdx ; matrix size n

loopRow:
    mov r10, r11
    mov r12, [rcx + 8 * r10 - 8] ; el.(64) of the matrix
    mov r13, [rcx + 8 * r11 - 8] ; el.(64) of the matrix

loopColumn:
    mov rdx, [rcx + 8 * r10 - 8]
    mov rsi, [rcx + 8 * r11 - 8]
    mov r8, rdx
    mov [rcx + 8 * r10 - 8], rsi
    mov [rcx + 8 * r11 - 8], rdx

    dec r10        ; Move to the next column
    jnz loopColumn
    dec r11        ; Move to the next row
    jnz loopRow

    ret
transpose ENDP
END
指针 程序集 x86-64 转置

评论

0赞 Erik Eidt 10/28/2023
好的,那么你有没有尝试过调试这个?从头开始,在程序开始时,里面有什么(与,.应该里面有什么)??rax
0赞 szyjas 10/28/2023
在开始时,rax 存储维度 n,而 rcx 将地址存储到矩阵
0赞 Erik Eidt 10/28/2023
您是否已通过调试器中的检查验证了这一点?
2赞 Erik Eidt 10/28/2023
我不知道任何在 .您在什么系统上运行?也许碰巧有一个看起来合乎逻辑的值,但只是在函数调用之前计算出的一些值。或者,也许我只是不知道这个 ABI。无论如何,添加到打印矩阵中,除了值之外还显示地址可能会有所帮助,尤其是当您似乎对矩阵使用锯齿数组时。raxraxmain
2赞 Erik Eidt 10/28/2023
好的,这里是调试复杂寻址模式的方法。拆分为两条指令,以便您可以查看有效地址。首先使用 ,然后 。这将允许您在 中查看实际使用的内存地址。将这些地址与 c 代码中的地址和值打印进行比较,以查看您是否正在访问合法位置。lea rax, [r9 + rdi * 8]mov rdx, [rax]rax

答:

1赞 Sep Roland 10/30/2023 #1

我看不出如何挽救当前的代码。

  • 你似乎在猜测争论在哪里。
  • 您正在使用 RDI 作为索引,而没有事先对其进行初始化。我想 0 是合适的,但即便如此,对列和行使用相同的缩放索引仍然是错误的。对于列,您需要步长 8(对应于 ),但对于行,您需要步长 64(对应于 )。rdi * 8inc rdiadd rdi, 8
  • 您正在使用内存中的一些值(矩阵中的元素)设置 R8 和 R9 寄存器,如果是 R8,您之后甚至不会使用它。对于 R9,您使用数组中的元素,就好像它是一个地址一样。
  • ...

前段时间,我在代码审查网站上发布了一个问答。您应该阅读它,因为它以图形方式显示了以下代码的作用。

; TransposeSquareMatrix(A, n)
    mov     rbx, rdi        ; Address A is in RDI
    mov     rcx, rsi        ; Dimension n is in RSI
    imul    r8, rsi, 8      ; Step between rows
    dec     rcx
    jz      .c              ; It's a (1 x 1) matrix
.a: push    rcx             ; (1)
    mov     rsi, rbx        ; Column address
    mov     rdi, rbx        ; Row address
.b: add     rsi, 8          ; To next element in this row
    add     rdi, r8         ; To next element in this column
    mov     rax, [rsi]      ; Swap 2 elements
    mov     rdx, [rdi]
    mov     [rdi], rax
    mov     [rsi], rdx
    dec     rcx
    jnz     .b
    lea     rbx, [rbx + r8 + 8] ; To next element on main diagonal
    pop     rcx             ; (1)
    dec     rcx
    jnz     .a              ; Continu until (1 x 1) matrix
.c: ret

评论

0赞 Sep Roland 11/4/2023
与其猜测,不如给我的解决方案一个机会?如果参数寄存器的选择困扰您,那么只需使用以下两条说明开始该过程:; TransposeSquareMatrix(A, n) mov rdi, rcx mov rsi, rdx
0赞 szyjas 11/7/2023
在给你的代码一个机会后,我在打印出未转置矩阵的第一行 0 1 2 3 时在这里遇到错误......7. 该错误表示:在 Project9 中的位置 0x00007FF6E5F5252B (1) 报告了以下异常.exe: 0xC0000005 (2):在位置 0x00000000FDFDFDFD (3) 读取时访问冲突。即使我不使用两个指令将 rcx、rdx 移动到 rdi 和 rsi 我仍然有错误,但位置0x00007FF6958D1E1D (1)、0xC0000005 (2) 和 0x0000000000000008 (3)std::cout << matrix[i][j] << " ";mov rax, [rsi]
1赞 Sep Roland 11/12/2023
@szyjas“在打印出未转置矩阵的第一行时” 那么即使在运行转置汇编代码之前?这是否意味着您的C++程序有问题?我相信我的汇编代码将就地转置四字矩阵,但前提是地址在 RDI 中,维度在 RSI 中。我无法帮助C++部分,所以我建议您发布一个包含整个程序最新版本的新问题,并确保强调使用C++的链接(用C ++标记它。
1赞 szyjas 11/13/2023
也许我应该更准确地说明我的意思。在运行 c++ 时,我在转置之前看到矩阵,然后只有第一行“转置”矩阵,然后才看到我上面写的错误。转置矩阵的第一行如下所示:0,1,2,3,4,5,6,7。如果您建议这可能是 c++ 部分的问题,那么我会问一个新问题。