从汇编代码和骨架 C 导出数组的大小
deriving size of array from assembly code and skeleton C
我正在尝试改进我的汇编编程,我遇到了这个导出函数中参数值的练习,但我不确定我应该如何使用给定的汇编代码来完成它.
这是令我感到困惑的汇编代码(尝试注释某些行):
arrayfunc:
leaq 15992(%rdx),%rax // get 1999th element frm Array2
leaq -8(%rdx),%r10 //start of Array2
movq %rcx,%r9 // store address of Array1 in rcx into r9
.L2:
leaq -400(%rdx), %r8 //Array2 - 50longs? but why minus 50longs
movq %r9,%rdx //move address in Array1[i][j] into rdx
.L3: //inner loop
movslq (%rdx),%rcx //move value in Array1[i][j] into rcx
subq ,%rax // increment j so becomes Array2[M-1-i][N-1-2j]
addq ,%rdx //increment address to Array1[i][2j]
movq %rcx,8(%rax)// what does this line do
cmpq %r8,%rax //compare j<N
jne .L3
addq 0,%r9 //Not sure what this line does with the 200
cmpq %r10,%rax
jne .L2
ret
这是给出的 C 代码:
void arrayfunc(int Array1[M][N], long Array2[M][N])
{
long i,j;
for(i=0;i<M;++i)
for(j=0;j<N;++j)
{
Array2[M-1-i][N-1-j] = Array1[i][j];
}
}
有人可以教我如何正确解释汇编,以便我可以准确地推导出 M 和 N 的值吗?我在解释这些台词时遇到了困难(不确定我是否评论正确,但有些台词我真的不确定所指示的情况)
请帮助我更好地理解这个 asm(注释代码会有很大帮助),因为我真的不知道如何找到 M 和 N 值。
感谢任何帮助。
由于这些代码中存在一些错误,这变得更加困难。第三个 leaq
只有一个操作数,因此缺少目标寄存器。 M
和 N
是常量,否则会有涉及变量(可能还有乘法)的代码用于索引(没有),但是 C 代码说 ++M
,这会不允许在常量上使用(应该改为 ++i)。
由于 M
和 N
是常数,所以 Array2[M-1][N-1]
处的元素是 Array2
的常数偏移量(指数组的最后一个元素) .由于它是在循环中使用的,代码在所谓的 loop invariant code motion 中计算该地址——一种优化技术,将一些 fixed/constant 计算重新定位到循环之外,预先执行而不是重复相同的事情循环的每次迭代。
从 Array2[M-1]
部分,我们导出 (M-1)*N
以获得最后一行的偏移量。从 [N-1]
部分,我们添加到 N-1
,然后将整个事情乘以 8,因为在 Array2
.
中每长 8 个字节
然后通过公式 ((M-1)*N+N-1)*8
和简化的 (M*N-1)*8
和 M*N*8-8
计算索引的常量部分的完整偏移量。因此 15992 = M*N*8-8
和 16000 = M*N*8
和 2000 = M*N
.
外循环每次迭代向前推进 200
字节,这对应于递增的 i
,用于 Array1
的第一个索引位置。由于 Array1
的第一个索引的 +1
映射到 200
字节,因此 Array1
的行的大小(以元素而非字节计)为 200/4
或 50
,因此 N=50
.
因为 N=50
我们可以推断 2000=M*50
因此 2000/50=40=M
.
基本上,一种方法是搜索代码以了解其计算方式 Array2[M-1-i][N-1-j]
。这是关键 b/c 它是使用 M
.
的汇编代码中的表达式
(Array1[i][j]
可能涉及 N
,但不涉及 M
— 但这里已经优化,author/compiler 识别访问模式是顺序的,因此不需要 i*N+j
,只需一个 运行 值,增量为 4)。
这不是微不足道的,因为已经应用了优化技术;这些将计算分散到代码的不同部分,而不是像人们可能期望的那样一起出现在一个地方。变量也被删除(或大量修改),用索引和循环控制变量代替指针。
这一行:movq %rcx,8(%rax)// what does this line do
将赋值写入 Array2
的内存,基本上是 Array2[][]=...
中的 =
运算符。一旦理解了这一点,我们就可以向后推理找到整个索引计算,其中部分展开,各种常量组合在一起。
(另一种方法是弄清楚 i<M
和 j<N
是如何完成的,尽管由于这些循环控制变量已更改为有利于指针,因此分析很重要,并且包括一些以上分析。)
循环一读一写,在C语言和汇编语言中都是如此。所以内存写一定是Array2
的一个元素赋值,内存读movslq (%rdx),%rcx
一定是从Array1
.
取一个元素
请注意,进一步优化可能会显着改变一些事情,例如循环展开和向量寄存器的使用。
我正在尝试改进我的汇编编程,我遇到了这个导出函数中参数值的练习,但我不确定我应该如何使用给定的汇编代码来完成它.
这是令我感到困惑的汇编代码(尝试注释某些行):
arrayfunc:
leaq 15992(%rdx),%rax // get 1999th element frm Array2
leaq -8(%rdx),%r10 //start of Array2
movq %rcx,%r9 // store address of Array1 in rcx into r9
.L2:
leaq -400(%rdx), %r8 //Array2 - 50longs? but why minus 50longs
movq %r9,%rdx //move address in Array1[i][j] into rdx
.L3: //inner loop
movslq (%rdx),%rcx //move value in Array1[i][j] into rcx
subq ,%rax // increment j so becomes Array2[M-1-i][N-1-2j]
addq ,%rdx //increment address to Array1[i][2j]
movq %rcx,8(%rax)// what does this line do
cmpq %r8,%rax //compare j<N
jne .L3
addq 0,%r9 //Not sure what this line does with the 200
cmpq %r10,%rax
jne .L2
ret
这是给出的 C 代码:
void arrayfunc(int Array1[M][N], long Array2[M][N])
{
long i,j;
for(i=0;i<M;++i)
for(j=0;j<N;++j)
{
Array2[M-1-i][N-1-j] = Array1[i][j];
}
}
有人可以教我如何正确解释汇编,以便我可以准确地推导出 M 和 N 的值吗?我在解释这些台词时遇到了困难(不确定我是否评论正确,但有些台词我真的不确定所指示的情况)
请帮助我更好地理解这个 asm(注释代码会有很大帮助),因为我真的不知道如何找到 M 和 N 值。
感谢任何帮助。
由于这些代码中存在一些错误,这变得更加困难。第三个 leaq
只有一个操作数,因此缺少目标寄存器。 M
和 N
是常量,否则会有涉及变量(可能还有乘法)的代码用于索引(没有),但是 C 代码说 ++M
,这会不允许在常量上使用(应该改为 ++i)。
由于 M
和 N
是常数,所以 Array2[M-1][N-1]
处的元素是 Array2
的常数偏移量(指数组的最后一个元素) .由于它是在循环中使用的,代码在所谓的 loop invariant code motion 中计算该地址——一种优化技术,将一些 fixed/constant 计算重新定位到循环之外,预先执行而不是重复相同的事情循环的每次迭代。
从 Array2[M-1]
部分,我们导出 (M-1)*N
以获得最后一行的偏移量。从 [N-1]
部分,我们添加到 N-1
,然后将整个事情乘以 8,因为在 Array2
.
然后通过公式 ((M-1)*N+N-1)*8
和简化的 (M*N-1)*8
和 M*N*8-8
计算索引的常量部分的完整偏移量。因此 15992 = M*N*8-8
和 16000 = M*N*8
和 2000 = M*N
.
外循环每次迭代向前推进 200
字节,这对应于递增的 i
,用于 Array1
的第一个索引位置。由于 Array1
的第一个索引的 +1
映射到 200
字节,因此 Array1
的行的大小(以元素而非字节计)为 200/4
或 50
,因此 N=50
.
因为 N=50
我们可以推断 2000=M*50
因此 2000/50=40=M
.
基本上,一种方法是搜索代码以了解其计算方式 Array2[M-1-i][N-1-j]
。这是关键 b/c 它是使用 M
.
(Array1[i][j]
可能涉及 N
,但不涉及 M
— 但这里已经优化,author/compiler 识别访问模式是顺序的,因此不需要 i*N+j
,只需一个 运行 值,增量为 4)。
这不是微不足道的,因为已经应用了优化技术;这些将计算分散到代码的不同部分,而不是像人们可能期望的那样一起出现在一个地方。变量也被删除(或大量修改),用索引和循环控制变量代替指针。
这一行:movq %rcx,8(%rax)// what does this line do
将赋值写入 Array2
的内存,基本上是 Array2[][]=...
中的 =
运算符。一旦理解了这一点,我们就可以向后推理找到整个索引计算,其中部分展开,各种常量组合在一起。
(另一种方法是弄清楚 i<M
和 j<N
是如何完成的,尽管由于这些循环控制变量已更改为有利于指针,因此分析很重要,并且包括一些以上分析。)
循环一读一写,在C语言和汇编语言中都是如此。所以内存写一定是Array2
的一个元素赋值,内存读movslq (%rdx),%rcx
一定是从Array1
.
请注意,进一步优化可能会显着改变一些事情,例如循环展开和向量寄存器的使用。