简体   繁体   English

从 C 程序调用 x86 汇编函数时检索到的矩阵值不正确

[英]Incorrect matrix value being retrieved when calling an x86 Assembly function from a C program

I am writing a C program that adds the values of two cells in two matrices.我正在编写一个 C 程序,它将两个矩阵中的两个单元格的值相加。 In my C program, I call an Assembly function that implements the function to add the two cells.在我的 C 程序中,我调用了一个 Assembly 函数,该函数实现了将两个单元格相加的函数。 That function has the following signature:该函数具有以下签名:

// 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);

Below is my C program ( main.c ): I am defining 2 dynamically allocated 3x3 matrices, with the bottom right corner of each matrix set to 3. I am intenting to add the bottom right corners through the function call:下面是我的 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;
}

Below is my x86 Assembly program ( addTwoCells.s ).下面是我的 x86 汇编程序( addTwoCells.s )。 I first process in all the parameters and then I try to retrieve the value of the cell at the bottom right corner of the first matrix.我首先处理所有参数,然后尝试检索第一个矩阵右下角单元格的值。 To do this, I first compute the flattened index corresponding to the bottom right corner (which after debugging is correct: 2*(column count) + 2 = 2*3 + 2 = 8 ).为此,我首先计算与右下角对应的扁平索引(调试后正确: 2*(column count) + 2 = 2*3 + 2 = 8 )。 However, when I try to retrieve the integer at that flattened index + the memory address of the first matrix ( matrixAStartingAddress ), the result is always a crazy large number (like 1478295976) when it should be 3 , as shown in the output of the function (stored in the EAX register).但是,当我尝试检索该扁平索引处的整数 + 第一个矩阵的内存地址( matrixAStartingAddress )时,结果总是一个疯狂的大数(如 1478295976),而它应该是 3 ,如输出所示函数(存储在 EAX 寄存器中)。 This seems strange, since it seems that I am processing the parameters correctly and am moving the value at the memory address %ecx through the expression (%ecx) , not the memory address itself:这看起来很奇怪,因为我似乎正在正确处理参数,并且正在通过表达式(%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

Problem 1: You forgot the starting memory address of matrix B. It should be parameter 6, and what you currently call parameters 6-9 should become 7-10.问题1:你忘记了矩阵B的起始内存地址,应该是参数6,你现在调用的参数6-9应该变成了7-10。

Problem 2: int s are 4 bytes wide in x86, but you're calculating the address of the cell as if they're only 1 byte wide.问题 2: int在 x86 中是 4 个字节宽,但是您正在计算单元格的地址,就好像它们只有 1 个字节宽一样。

Problem 3: You're passing a double pointer from C to addTwoCells , but your assembly code treats it like it's a 2D array.问题 3:您将双指针从 C 传递给addTwoCells ,但您的汇编代码将其视为二维数组。 These are not compatible types.这些不是兼容的类型。 Try compiling these two C functions and comparing the resulting assembly :尝试编译这两个 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];
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM