0
int A[R][S][T];

int A[R][S][T];
int store_ele(int i, int j, int k, int *dest) {
    *dest = A[i][j][k];
    return sizeof(A);
}

Gcc 生成以下汇编代码:

1.  movl 8(%ebp), %ecx
2.  movl 12(%ebp), %eax
3.  leal (%eax, %eax, 8), %eax
4.  movl %ecx, %edx
5.  sall $6, %edx
6.  sub1 %ecx, %edx
7.  addl %edx, %eax
8.  addl 16(%ebp), %eax
9.  movl A(,%eax,4), %edx
10. movl 20(%ebp), %eax
11. movl %edx, (%eax)
12. movl $2772, %eax

问题:http: //i.imgur.com/szB1XnE.jpg

我不明白上面汇编代码中的第 9 行和这些问题。

4

1 回答 1

1

通过一次查看一行代码,最容易解释发生了什么。

1.  movl 8(%ebp), %ecx

这将使用 ebp+8 处的参数加载 ecx,即i.

2.  movl 12(%ebp), %eax

这将使用 ebp+12 处的参数加载 eax,即j.

3.  leal (%eax, %eax, 8), %eax

这将 eax 设置为 eax+eax*8,基本上将自身乘以 9。所以 eax 现在是j*9

4.  movl %ecx, %edx

这会将 edx 设置为 ecx,即i.

5.  sall $6, %edx

这会将其左移 6 位,将其乘以 64,因此 edx 现在是i*64.

6.  sub1 %ecx, %edx

但是现在我们从该值中减去 ecx(即i),所以 edx 变为i*63

7.  addl %edx, %eax

这将 edx( i*63) 添加到 eax( j*9),所以 eax 现在是i*63 + j*9

8.  addl 16(%ebp), %eax

这在 ebp+16 处添加了参数k,即 eax 现在是i*63 + j*9 + k

9.  movl A(,%eax,4), %edx

这是使用A偏移量 eax*4 访问数组并将其存储在 edx 中。

由于 eax 是i*63 + j*9 + k,您可以将其视为在 offset 处访问单个维度 int 数组i*63 + j*9 + k。我们乘以 4,因为那是 int 的大小。

请注意,您可以将该索引表达式重写为i*7*9 + j*9 + k. 从那开始,我希望你可以开始了解数组的各个维度是如何被访问的。

10. movl 20(%ebp), %eax

这将使用 ebp+20 处的参数加载 eax,即dest.

11. movl %edx, (%eax)

这会将我们刚刚从数组中得到的 edx 存储在 eax ( dest) 中的地址处。*dest = A[i*7*9 + j*9 + k]如果A是一维 int 数组,它会有效地做;

12. movl $2772, %eax

这只是返回值 2772,大小为A.

既然您现在知道 的大小A,如果您回顾一下在取消引用数组时是如何乘以和乘以的i,我希望您可以很容易地计算出,和的值。jkRST

更新:计算尺寸

如果您的数组的维度是R,ST,那么要访问 , , 处的元素,i您将使用什么公式?jk

将数组视为具有维度的大型三维块R x S x T。索引从该i块中选择一个二维切片,其维度为S x T。索引从该j长度切片中选择一行T。并且k索引只是该k行中的第一项。

所以一维地址可以表示为i*S*T + j*T + k。现在,如果您回顾上面反汇编中的数组计算,您是否没有注意到相同的模式?你能看到反汇编映射到S和的哪些值T吗?

至于查找R:你知道数组中的项目数是693(2772字节大小除以4的int大小);而且您还知道可以使用R*S*T(再次考虑三维块)来计算项目的数量。因此R*S*T = 693和 你知道ST,所以找到R只是一个除法的问题。

于 2013-05-12T17:41:18.463 回答