从 C 程序调用 x86 汇编函数时检索到的矩阵值不正确
Incorrect matrix value being retrieved when calling an x86 Assembly function from a C program
我正在编写一个 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
问题一:你忘记了矩阵B的起始内存地址,应该是参数6,你现在所说的参数6-9应该变成7-10。
问题 2:int
在 x86 中是 4 个字节宽,但您计算单元格的地址时就好像它们只有 1 个字节宽一样。
问题 3:您正在将一个双指针从 C 传递到 addTwoCells
,但您的汇编代码将其视为一个二维数组。这些不是兼容的类型。尝试 compiling these two C functions and comparing the resulting assembly:
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];
}
我正在编写一个 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
问题一:你忘记了矩阵B的起始内存地址,应该是参数6,你现在所说的参数6-9应该变成7-10。
问题 2:int
在 x86 中是 4 个字节宽,但您计算单元格的地址时就好像它们只有 1 个字节宽一样。
问题 3:您正在将一个双指针从 C 传递到 addTwoCells
,但您的汇编代码将其视为一个二维数组。这些不是兼容的类型。尝试 compiling these two C functions and comparing the resulting assembly:
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];
}