汇编指令阅读,leaq

Assembly instruction reading, leaq

因此我尝试使用给定的汇编代码计算以下代码中 M 和 N 的值。

int array1[M][N];
int array2[N][M];

void copyelement(int i, int j) {
    array1[i][j] = array2[j][i];
}

程序集:


copyelement:
    movslq      %esi, %rsi
    movslq      %edi, %rdi
    leaq        (%rdi,%rdi,8), %rax
    addq        %rsi, %rax
    leaq        (%rsi,%rsi,2), %rdx
    leaq        (%rsi,%rdx,4), %rdx
    addq        %rdx, %rdi
    leaq        array2(%rip), %rdx
    movl        (%rdx,%rdi,4), %ecx
    leaq        array1(%rip), %rdx
    movl        %ecx, (%rdx,%rax,4)
    ret

一边看汇编代码,一边读到array2(%rip),然后就不知道怎么继续了。

此时,根据我的计算我应该
%rdx = %rdi + (%rsi + %rax) + 4*((%rsi+%rax) + 2*(%rsi + %rax)).

我也不太确定如何从中获取数组大小。

I got through till array2(%rip) and then I didn't know how to move forward.

使用该指令,array2(或array2[0][0])的地址被写入rdx寄存器。忘记 rip 在这里注册。

该指令加上后面的指令 (movl) 的组合将读取数组元素 ((int *)array2)[rdi]。下面的两条指令将写入数组元素 ((int *)array1)[rax].

这意味着 rdi 包含值 M*j+irax 包含值 N*i+j

如果代码是为 System-V 编译的,rdi 最初包含 i 的值,rsi 最初包含 j 的值。

编辑

okay I tried again, but I can't retrieve the exact value of M and N because the registers don't have any values loaded :/ am I missing something?

首先我们检查 i=0, j=1:

这意味着 edi 最初是 0esi 最初是 1

如果我没记错的话,rdileaq array2 ...指令之前是13。

这意味着M*j+i = M*1+0 = M = 13.

然后我们用i=1, j=0检查一下。

如果我没记错的话,raxleaq array2 ...指令之前是9。

这意味着N*i+j = N*1+0 = N = 9.

这是带有注释的说明,说明了它们的作用。

// Initially, edi contains i and esi contains j.

movslq %esi, %rsi          // Sign-extended 32-bit j to 64 bits.
movslq %edi, %rdi          // Sign-extended 32-bit i to 64 bits.
leaq   (%rdi,%rdi,8), %rax // rax = rdi + rdi*8 = 9*rdi = 9*i.
addq   %rsi, %rax          // rax = rax + rsi = 9*i + j.
leaq   (%rsi,%rsi,2), %rdx // rdx = rsi + rsi*2 = 3*rsi = 3*j.
leaq   (%rsi,%rdx,4), %rdx // rdx = rsi + rdx*4 = j + (3*j)*4 = 13*j.
addq   %rdx, %rdi          // rdi = rdi + rdx = i + 13*j = i + 13*j.
leaq   array2(%rip), %rdx  // rdx = array2 (address of first element).
movl   (%rdx,%rdi,4), %ecx // Load *(rdx + rdi*4) = array2[rdi] = array2[i + 13*j] into ecx.
leaq   array1(%rip), %rdx  // rdx = array1 (address of first element).
movl   %ecx, (%rdx,%rax,4) // Store ecx into (rdx + rax*4) = array1[rax] = array1[9*i + j].

因此,C 代码中的 array2[j][i] 是汇编代码中的 array2[i + 13*j](考虑到二维寻址与一维寻址)。后者应该是array2[i + M*j],所以我们可以得出M是13.

同理,C代码中的array1[i][j]就是汇编代码中的array1[9*i + j]。后者应该是array1[N*i + j],所以我们可以得出结论N是9.