Сборка: инструкция CMOVB в сборке Intel x86-64 - PullRequest
0 голосов
/ 08 ноября 2018

Я немного озадачен тем, что "cmovb" делает в этом коде сборки

leal   (%rsi, %rsi), %eax  // %eax <- %rsi + %rsi
cmpl   %esi, %edi          // compare %edi and %esi
cmovb  %edi, %eax
ret

и код C для этого:

int foo(unsigned int a, unsigned int b)
{
    if(a < b) 
        return a;
    else
        return 2*b;
}

Может кто-нибудь помочь мне понять, как cmovb работает здесь?

Ответы [ 2 ]

0 голосов
/ 08 ноября 2018

Как прокомментировал вопрос Джестер, семейство команд cmov* - это условные перемещения, соединенные через регистр flags с предыдущей операцией (сравнения).

Вы можете использовать, например, документацию Intel в качестве справочного материала для набора команд x86-64 / AMD64. Инструкции условного перемещения приведены на стр. 172 объединенного тома.

cmovb, cmovnae и cmovc все работают одинаково: если установлен флаг переноса, они перемещают исходный операнд в целевой операнд. В противном случае они ничего не делают.

Если мы затем посмотрим на предыдущие инструкции, которые влияют на флаги, то увидим, что инструкция cmp (суффикс l является частью синтаксиса AT & T и означает, что аргументы являются "длинными"), изменяет набор флаги в зависимости от разницы между двумя аргументами. В частности, если второе меньше первого (в синтаксисе AT & T), устанавливается флаг переноса, в противном случае флаг переноса сбрасывается; как если бы вычитание было выполнено без сохранения результата где-либо. (Инструкция cmp влияет и на другие флаги, но они игнорируются кодом.)

0 голосов
/ 08 ноября 2018

C MOV B = Условное ПЕРЕМЕЩЕНИЕ, если ниже (установлен флаг переноса). Он буквально делает то, что говорит, если условие выполнено, двигайтесь. Условие равно a<b, а перемещенное значение равно 2*b

ABI сохраняет возвращаемое значение в %edi, поэтому сначала сохраняет a, а затем условно перезаписывает его 2*b.

...