【问题标题】:x86 assembly code confusionx86 汇编代码混淆
【发布时间】:2015-03-21 18:05:48
【问题描述】:

我们刚刚开始讨论关于装配的话题,而我在这个问题上被困的时间最长。鉴于以下情况,我必须将程序集转换为 C 代码:

C 代码:

int foo(int *a, int n, int val) {
    int i;
    for (i = _________; ____________________________ ; i =___________) {
        ;
    }
    return i;
}

组装:

// what I've gathered so far
foo()
:
foo:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%ecx  // ecx: a
movl 16(%ebp),%edx  // edx: val
movl 12(%ebp),%eax  // eax: n
decl %eax  // n = n--
js .L3  // if n < 0 goto done
.L7:  // loop
cmpl %edx,(%ecx,%eax,4)  // I don't understand how you would compute the
// address for (%ecx,%eax,4) I know it would be %ecx + %eax*4 = %ecx + eax << 2
jne .L3  // if (%ecx, %eax, 4) != val goto done (?)
decl %eax  // n = n--
jns .L7  // if (n >= 0) jump to loop
.L3:  // done
movl %ebp,%esp
popl %ebp
ret

我不知道如何弄清楚 i 被初始化为什么以及循环的主体是什么。我假设 i = n 因为 n 作为更新。似乎有两个条件,一个是 n > 0,另一个是 cmpl 线。如果我对代码的理解不正确,请纠正我,非常感谢任何有关此问题的线索。

【问题讨论】:

  • 它在一个数组中寻找一个值,但我不会为你写一个实际上相当简单的循环。小心结束条件!。
  • ...循环的主体是什么:在 C 中,循环可以没有主体。根据您的 C 模式中显示的形式,情况似乎如此。所有有趣的工作都是在初始条件(第一个__)、测试条件(第二个__)和“增量”语句(第三个__)中完成的。
  • 编译器设法为函数中的所有局部变量使用寄存器。这是一个简单的循环,你几乎做对了。 for 语句中的第一个和最后一个表达式非常简单,条件表达式测试 2 个条件。还要记住a 是一个指向ints 数组的指针。
  • 另一个线索:这个循环的编写方式很麻烦。您可以简化它以保持相同的语义,同时删除更新(第三个)表达式并使编译的代码更短。
  • @chqrlie 我的猜测是发布的 C 代码是作业所需的模板。

标签: c assembly x86 intel


【解决方案1】:

我本可以犯一些错误,但基本上是这样的:

int foo(int *a, int n, int val) {
    int i;
    for (i = n - 1; i >= 0 && a[i] == val; i = i - 1) {
        ;
    }
    return i;
}

i%eax 寄存器;它从 n - 1 循环到 0。cmpl 索引访问 (%ecx,%eax,4) 以字节为单位 - 这相当于 a[i],因为 ia32 上 int 的大小为 4 个字节。因此寻址的 4 个字节与 val 进行比较。

%eax 被隐式返回。

还要注意,js 表示 &lt; 0jns &gt;= 0


另一种写法:

    i = n;
    i --;               //  decl %eax
    if (i < 0) {
        goto L3;        //  js .L3
    }
L7:
    if (a[i] != val)    // cmpl %edx,(%ecx,%eax,4)
        goto L3;        // jne .L3

    i --;               // decl %eax
    if (i >= 0)
        goto L7;        // jns .L7

L3:
    return i;

【讨论】:

  • 是不是行:cmpl %edx,(%ecx,%eax,4) jne .L3 说如果a[i] != val,跳转到L3(也就是结束码)?为什么会在for循环中继续?
  • 当然 cmets 有点偏离,因为 cmpl+jne 一起就是 if
  • @AnttiHaapala 上面的评论者试图在没有实际做功课的情况下提供帮助。投反对票。
  • OP 表现出对程序集的理解,但在这种情况下对如何将其转换为 C 感到迷茫 - 鉴于主题是理解程序集,那么将其转换为 C 至多是肤浅的。
  • 不是一次性错误,而是测试表达式中的变量名错误。使用这个:for (i = n - 1; i &gt;= 0 &amp;&amp; a[i] == val; i = i - 1)
【解决方案2】:

使用预处理器的替代方法:

#define _________ n - 1
#define ____________________________  i >= 0 && a[i] == val
#define ___________  i + 1

int foo(int *a, int n, int val) {
    int i;
    for (i = _________; ____________________________ ; i =___________) {
        ;
    }
    return i;
}

当然,您只能将其用于娱乐或取笑新程序员;-)

【讨论】: