“ shld”指令产生奇怪的值

时间:2019-04-08 00:04:28

标签: c++ c gcc assembly inline-assembly

我在由g ++(7.3.0)编译的内联汇编中使用“ shld”指令。 会产生一些奇怪的结果。

在Ubuntu和WSL上尝试过。

   unsigned long long hi, lo;
   //some code goes here
   //...
   asm volatile (
    "shld $0x3, %1, %0;\n"
    : "=r"(hi)
    : "r"(lo)
    :
    );
   //I expect the asm produces this:
   //hi = (hi << 3) | (lo >> 61);
   //but the actual result is:
   //hi = (lo << 3) | (lo >> 61);
   //you can see the real assembly produced by gcc below.

我希望“ hi”中的结果值为

(hi << 3) | (lo >> 61)

但是实际结果是

(lo << 3) | (lo >> 61)

有关详细信息,请参见https://en.wikibooks.org/wiki/X86_Assembly/Shift_and_Rotate

事实证明,g ++将我的代码转换为:

    6e6a:       48 8b 45 a0             mov    -0x60(%rbp),%rax
    6e6e:       48 0f a4 c0 03          shld   $0x3,%rax,%rax
    6e73:       48 89 45 98             mov    %rax,-0x68(%rbp)

其中-0x60(%rbp)为'lo',而-0x68(%rbp)为'hi'。

1 个答案:

答案 0 :(得分:5)

您需要指定hi既是输入也是输出。像这样:

asm volatile (
"shld $0x3, %1, %0;\n"
: "=r"(hi)
: "r"(lo)
, "0"(hi)
:
);

产生以下汇编代码:

mov    -0x10(%rbp),%rdx
mov    -0x8(%rbp),%rax
shld   $0x3,%rdx,%rax
mov    %rax,-0x8(%rbp)

“ 0”表示此操作数(数字2)必须与操作数0相同,这似乎没有用,只是它使该寄存器既是输入又是输出。