从汇编代码和骨架 C 导出数组的大小

Posted

技术标签:

【中文标题】从汇编代码和骨架 C 导出数组的大小【英文标题】:deriving size of array from assembly code and skeleton C 【发布时间】:2021-11-27 09:35:12 【问题描述】:

我正在尝试改进我的汇编编程,并且我遇到了这个用于推导此函数中参数值的练习,但我不确定我应该如何使用给定的汇编代码来做这件事。

这是我感到困惑的汇编代码(尝试评论一些行):

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    $8,%rax     // increment j so becomes Array2[M-1-i][N-1-2j]
    addq    $4,%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    $200,%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];
        

有人可以教我如何正确解释 asm,以便我可以准确地得出 M 和 N 的值吗?我在解释这些行时遇到了困难(不确定我是否评论正确,但有些行我真的不确定发生了什么)

请帮助我更好地理解这个 asm(注释代码会很有帮助),因为我真的不知道如何找到 M 和 N 值。

感谢任何和所有的帮助。

【问题讨论】:

【参考方案1】:

由于这些代码中存在一些错误,这一点变得更加困难。第三个leaq 只有一个操作数,所以缺少一个目标寄存器。 MN 是常量,否则会有涉及用于索引的变量(可能还有乘法)的代码(没有),但 C 代码显示 ++M,这在常量上是不允许的(这应该是 ++i)。

由于MN 是常量,所以Array2[M-1][N-1] 处的元素是Array2 的常量偏移量(指的是数组的最后一个元素)。由于这是在循环中使用的,因此代码会在所谓的loop invariant code motion 中计算该地址——这是一种优化技术,可以将一些固定/常数计算移出循环,提前完成,而不是在每次迭代时重复相同的事情。循环。

Array2[M-1] 部分,我们派生(M-1)*N 以获取最后一行的偏移量。从[N-1] 部分,我们添加到N-1,然后将整个乘以8,因为Array2 中每长有8 个字节。

然后通过公式((M-1)*N+N-1)*8 计算索引中该常量部分的完整偏移量,并简化为(M*N-1)*8M*N*8-8。因此15992 = M*N*8-816000 = M*N*82000 = M*N

外部循环每次迭代都会向前步进200 字节,这对应于递增的i,用于Array1 的第一个索引位置。由于Array1 的第一个索引的+1 映射到200 字节,所以Array1 行的大小(以元素而不是字节为单位)为200/450,因此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——但这里已经优化,作者/编译器识别访问模式是顺序的,所以不需要i*N+j,只是一个运行值以 4 为增量)。

这不是微不足道的,因为已经应用了优化技术;这些将计算分散到代码的不同部分,而不是像人们可能期望的那样一起出现在一个地方。变量也被消除(或大量修改),用索引和循环控制变量代替指针。

这一行:movq %rcx,8(%rax)// what does this line do 将赋值写入Array2 的内存,基本上是Array2[][]=... 中的= 运算符。一旦理解了这一点,我们就可以向后推理以找到整个索引计算,其中部分展开并组合了各种常量。

(另一种方法是弄清楚i&lt;Mj&lt;N 是如何完成的,尽管由于这些循环控制变量已更改为有利于指针,因此分析并非易事,并包括上述一些分析。)

在 C 语言和汇编语言中,循环具有一次读取和一次写入。因此,内存写入必须是赋值给Array2的一个元素,而内存读取movslq (%rdx),%rcx必须是从Array1取一个元素。

请注意,进一步的优化可能会显着改变一些事情,例如循环展开和向量寄存器的使用。

【讨论】:

以上是关于从汇编代码和骨架 C 导出数组的大小的主要内容,如果未能解决你的问题,请参考以下文章

需要骨架代码从 PythonWin 调用 Excel VBA

前端开发者的福音:根据UI设计图自动生成GUI骨架代码

SpringCloud应用骨架开发

SpringCloud应用骨架开发

如何修复对象具有未应用的转换。这对于带有骨架的网格永远不起作用。出口取消

在vue项目中使用骨架屏