инструкция "shld" выдает странное значение - PullRequest
1 голос
/ 08 апреля 2019

Я использую инструкцию "shld" в inline-сборке, скомпилированной g ++ (7.3.0).Это выдает странный результат.

Пробовал в 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)

Но фактический результатis

(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 Ответ

5 голосов
/ 08 апреля 2019

Необходимо указать, что 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,который кажется бесполезным, за исключением того, что он делает этот регистр и входом, и выходом.

...