汇编语言到 C 问题与寄存器

Assembly Language to C issue with registers

我正在尝试编写 C 代码,其效果等同于以下汇编代码:

addq %rsi, %rdi
imulq %rdx, %rdi
movq %rdi, %rax
sarq , %rax
salq , %rax
andq %rdi, %rax
ret

有函数原型

长解码(长x,长y,长z)

参数 x、y 和 z 在寄存器 %rdi、%rsi 和 %rdx 中传递。该代码将 return 值存储在寄存器 %rax 中。

到目前为止,我有以下 C 代码:

long decode(long x, long y, long z)
{
  long w;

  x = x+y;
  x = x*z;

  w = x;
  w = ((x>>15)<<31);

  return x&w;
}

其中,当使用 gcc -O2 -S -c filename.c 编译时产生以下内容:

addq %rdi, %rsi
imulq %rdx, %rsi
movq %rsi, %rax
sarq , %rax
salq , %rax
andq %rsi, %rax
ret

显然,寄存器 %rdi 和 %rsi 被交换了。

所以,如果我通过交换 x 和 y 来更改函数,它看起来像这样:

long decode4(long x, long y, long z)
{
  long w;

  y = x + y;
  y = y * z;

  w = y;
  w = ((y>>15)<<31);

  return y&w;
}

并且,程序集再次如下所示:

 addq %rdi, %rsi
 imulq %rdx, %rsi
 movq %rsi, %rax
 sarq , %rax
 salq , %rax
 andq %rsi, %rax
 ret

y 和 x 的交换,并没有改变生成的汇编代码中的任何东西。 关于如何解决该问题的任何想法? 谢谢!

编译器已优化您的代码,因此在交换 x 和 y 后您看不到汇编代码有任何差异。

您的代码被编译器处理如下,

long decode4(long x, long y, long z)
{
    long w;
    // y = x + y;
    // y = y * z;
    // w = y;

    // The above three lines are combined as
    x = (x + y)*z; // result of addition and multiplication in rsi
    w = x; // move the above result to rax

    //w = ((y>>15)<<31);
    //return y&w;

    //The above two lines are treated as
    w = ((w>>15)<<31); // shift operations on rax
    return x&w; // rax and rsi
}

x 或 y 的变化不会影响此函数的预期行为,因此编译器对其进行了优化。

希望对您有所帮助。

您也可以尝试使用优化 O0(无优化)编译您的代码,然后您可以看到汇编代码的变化如您所愿。

您对代码的解读确实没有任何问题:

long decode(long x, long y, long z)
{
  long w;

  x = x+y;
  x = x*z;

  w = x;
  w = ((x>>15)<<31);

  return x&w;
}

它可以简化一点,但它没有任何问题,因为输出仅在所用寄存器的反转方面有所不同。可观察到的结果将是相同的。您声明此要求:

I am trying to write C code that will have an effect equivalent to the following assembly

两者等价所以我相信你的解决方案已经满足了作业。


有时这种类型的事情可以归结为所使用的编译器。我注意到我可以使用 GCC 4.6.4 和 -O2 优化级别获得您正在寻找的确切输出。您可以在 godbolt 上使用此代码,输出为:

decode:
        addq    %rsi, %rdi
        imulq   %rdx, %rdi
        movq    %rdi, %rax
        sarq    , %rax
        salq    , %rax
        andq    %rdi, %rax
        ret

这似乎与您课程的输出完全匹配。使用相同版本的 GCC (4.6.4) 您可以获得相同的输出:

long decode(long x, long y, long z)
{
  x = (x + y) * z;
  return x & ((x >> 15) << 31);
}