【问题标题】:Assembly instruction reading, leaq组装说明阅读,泄漏
【发布时间】:2020-10-02 04:49:22
【问题描述】:

所以我尝试使用给定的汇编代码计算以下代码中 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))

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

【问题讨论】:

  • 不要通过删除 asm 来破坏您的问题。没有它,它作为示例对未来的读者没有用处。

标签: c assembly x86-64 reverse-engineering


【解决方案1】:

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

// 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。

【讨论】:

    【解决方案2】:

    我熬到array2(%rip),然后我不知道如何继续前进。

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

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

    这意味着rdi 包含值M*j+i,而rax 包含值N*i+j

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

    编辑

    好的,我又试了一次,但我无法检索 M 和 N 的确切值,因为寄存器没有加载任何值:/我错过了什么吗?

    首先我们检查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

    【讨论】:

    • 嗯,我明白了,谢谢。所以我不能准确地得到 M 和 N 的值?我假设偏移值可能提供了一些信息。如果有帮助,它是在运行 Linux 的 x86_64 机器上编译的
    • 好吧,我又试了一次,但我无法检索 M 和 N 的确切值,因为寄存器没有加载任何值:/我错过了什么吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-16
    相关资源
    最近更新 更多