首页 > 解决方案 > 从 C 程序调用 x86 汇编函数时检索到的矩阵值不正确

问题描述

我正在编写一个 C 程序,它将两个矩阵中的两个单元格的值相加。在我的 C 程序中,我调用了一个汇编函数,该函数实现了添加两个单元格的函数。该函数具有以下签名:

// Adds two matrix cells together and returns the result
int addTwoCells(int **matrixA, int aRows, int aColumns, int cellARow, int cellAColumn,
        int **matrixB, int bRows, int bColumns, int cellBRow, int cellBColumn);

下面是我的 C 程序 ( main.c): 我正在定义 2 个动态分配的 3x3 矩阵,每个矩阵的右下角设置为 3。我打算通过函数调用添加右下角:

#include <stdio.h>
#include <stdlib.h>

// Adds two matrix cells together and returns the result
int addTwoCells(int **matrixA, int aRows, int aColumns, int cellARow, int cellAColumn,
        int **matrixB, int bRows, int bColumns, int cellBRow, int cellBColumn);

int main(void) {
    // Define the dimensions for matrix A
    int rA = 3;
    int cA = 3;

    // Define the double pointer that defines matrix A
    int **matrixA;
    // Dynamically allocate space for the entire matrix
    matrixA = (int**) malloc(rA * sizeof(int*));
    // Dynamically allocate sufficient space for each row in the entire matrix
    for (int i = 0; i < rA; i++) {
        matrixA[i] = (int*) malloc(cA * sizeof(int));
    }

    matrixA[2][2] = 3;

    // Define the dimensions for matrix B
    int rB = 3;
    int cB = 3;

    // Define the double pointer that defines matrix B
    int **matrixB;
    // Dynamically allocate space for the entire matrix
    matrixB = (int**) malloc(rB * sizeof(int*));
    // Dynamically allocate sufficient space for each row in the entire matrix
    for (int i = 0; i < rB; i++) {
        matrixB[i] = (int*) malloc(cB * sizeof(int));
    }

    matrixB[2][2] = 3;

    // Test calling the matrix multiplication function using the static library
    // compiled from the Assembly file
    printf("%d\n", addTwoCells(matrixA, rA, cA, 2, 2, matrixB, rB, cB, 2, 2));

    return EXIT_SUCCESS;
}

下面是我的 x86 汇编程序 ( addTwoCells.s)。我首先处理所有参数,然后尝试检索第一个矩阵右下角的单元格的值。为此,我首先计算对应于右下角的展平索引(调试后是正确的:)2*(column count) + 2 = 2*3 + 2 = 8。但是,当我尝试检索该扁平索引处的整数 + 第一个矩阵 ( matrixAStartingAddress) 的内存地址时,结果总是一个疯狂的大数字(如 1478295976),而它应该是 3,如函数的输出所示(存储在 EAX 寄存器中)。这看起来很奇怪,因为似乎我正在正确处理参数并且正在%ecx通过表达式移动内存地址处的值(%ecx),而不是内存地址本身:

# Function signature:
# int addTwoMatrixCells(int **matrixA, int aRows, int aColumns, int cellARow, int cellAColumn,
# int **matrixB, int bRows, int BColumns, int cellBRow, int cellBColumn)

.data
    # Matrix A dimensions
    aRows:
        .int 0

    aColumns:
        .int 0

    # Coordinate of cell A
    cellARow:
        .int 0

    cellAColumn:
        .int 0

    # Matrix B dimensions
    bRows:
        .int 0

    bColumns:
        .int 0

    # Coordinate of cell B
    cellBRow:
        .int 0

    cellBColumn:
        .int 0

    # The starting memory address of matrix A
    matrixAStartingAddress:
        .int 0

    # The starting memory address of matrix B
    matrixBStartingAddress:
        .int 0

.text
# Defining a function addTwoMatrixCells
.global addTwoCells
addTwoCells:
    # Prologue
    push %ebp
    movl %esp, %ebp

    # Process in parameter 1: the starting memory address of matrix A
    movl 8(%ebp), %ecx
    movl %ecx, matrixAStartingAddress

    # Process in parameter 2: the number of rows in matrix A
    movl 12(%ebp), %ecx
    movl %ecx, aRows

    # Process in parameter 3: the number of columns in matrix A
    movl 16(%ebp), %ecx
    movl %ecx, aColumns

    # Process in parameter 4: the row index of cellA
    movl 20(%ebp), %ecx
    movl %ecx, cellARow

    # Process in parameter 5: the column index of cellA
    movl 24(%ebp), %ecx
    movl %ecx, cellAColumn

    # Process in parameter 6: the number of rows in matrix B
    movl 28(%ebp), %ecx
    movl %ecx, bRows

    # Process in parameter 7: the number of columns in matrix B
    movl 32(%ebp), %ecx
    movl %ecx, bColumns

    # Process in parameter 8: the row index of cellB
    movl 36(%ebp), %ecx
    movl %ecx, cellBRow

    # Process in parameter 9: the column index of cellB
    movl 40(%ebp), %ecx
    movl %ecx, cellBColumn

    # Compute the flattened index of the cell in matrix A
    # One of the arithmetic operators needs to be in a CUP register
    # In this case, we designate ECX register to store the number of columns
    # in matrix A (n) initially, but ECX after the computation will store
    # the memory address of cellA in the matrix
    movl aColumns, %ecx
    imul cellARow, %ecx
    addl cellAColumn, %ecx
    addl matrixAStartingAddress, %ecx
    movl (%ecx), %eax

    # Compute the flattened index of the cell in matrix B

    # Epilogue
    movl %ebp, %esp
    pop %ebp
    ret

标签: cassemblyx86att

解决方案


问题一:你忘记了矩阵B的起始内存地址,应该是参数6,你现在所说的参数6-9应该变成了7-10。

问题 2:ints 在 x86 中是 4 个字节宽,但是您正在计算单元格的地址,就好像它们只有 1 个字节宽一样。

问题 3:您将双指针从 C 传递到addTwoCells,但您的汇编代码将其视为 2D 数组。这些不是兼容的类型。尝试编译这两个 C 函数并比较生成的程序集

int readValuePtr(int rows, int cols, int cellRow, int cellCol, int **matrix) {
    return matrix[cellRow][cellCol];
}

int readValueArr(int rows, int cols, int cellRow, int cellCol, int matrix[rows][cols]) {
    return matrix[cellRow][cellCol];
}

推荐阅读