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行和这些问题。
答案 0 :(得分: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
这是使用偏移量eax * 4访问A
数组并将其存储在edx中。
由于eax为i*63 + j*9 + k
,您可以将其视为访问偏移i*63 + j*9 + k
处的单个维度int数组。我们乘以4,因为这是int的大小。
请注意,您可以将该索引表达式重写为i*7*9 + j*9 + k
。从那以后,我希望你能开始看到如何访问数组的各个维度。
10. movl 20(%ebp), %eax
此加载eax的参数为ebp + 20,即dest
。
11. movl %edx, (%eax)
这将存储edx,我们刚从数组中获取的内容,位于eax(dest
)中的地址。如果*dest = A[i*7*9 + j*9 + k]
是单维int数组,它实际上正在A
;
12. movl $2772, %eax
这只是返回值2772,即A
的大小。
由于你现在知道A
的大小,如果你回顾一下i
,j
和k
在解除引用数组时的倍数,我就是希望你能够很容易地找出R
,S
和T
的值。
更新:计算尺寸
如果您的数组的维度为R
,S
和T
,那么要访问i
,j
,{{1}的元素你将使用什么公式?
将数组视为维度为k
的大三维块。 R x S x T
索引从该块中选择维度为i
的二维切片。 S x T
索引从长度为j
的切片中选择一行。 T
索引只是该行中的k
项。
因此,一维地址可以表示为k
。现在,如果您回顾上面反汇编中的数组计算,您是否注意到相同的模式?您能看到反汇编映射中的哪些值为i*S*T + j*T + k
和S
吗?
至于查找T
:你知道数组中的项数是693(2772字节大小除以int大小4);并且您还知道可以使用R
计算项目数(再次考虑三维块)。因此R*S*T
并且您知道R*S*T = 693
和S
,因此查找T
只是一个划分问题。