Go, сборка x64 и CMOVLMI: Где описан этот опкод?

Я читал исходный код Go, как и все, и когда я читал функцию fastrand(), которая для моей машины находилась бы в файле asm_amd64.s, я наткнулся на этот фрагмент:

    XORL    $0x88888eef, DX
    CMOVLMI BX, DX
    MOVL    DX, m_fastrand(AX)

Хоть убей, я не могу понять, что CMOVLMI должен делать. Его поиск показывает, что только Go, кажется, что-то знает об этом; Я могу найти множество кодов операций CMOVxx, определенных в справочнике AMD X86_64, и на странице Википедии есть длинная история инструкций условного перемещения, но этого нет нигде в этом списке.

Где определяется CMOVLMI? Является ли он уникальным для внутреннего ассемблера Go?


person Elf Sternberg    schedule 09.12.2016    source источник
comment
Вероятно, это CMOVS с 32-битными операндами. То есть CMOVS EDX, EBX в стандартной сборке Intel. Я не знаю, потрудится ли Go где-нибудь задокументировать свой причудливый язык ассемблера.   -  person Ross Ridge    schedule 09.12.2016
comment
Во что он дизассемблируется, если вы создаете бинарный файл и используете обычный дизассемблер для синтаксиса NASM или GAS? (например, objdump -drwC foo.o для получения синтаксиса AT&T, который наиболее близок к тому, что использует Go). L является допустимым кодом условия (меньше чем), и он также используется в качестве суффикса размера операнда в синтаксисе AT&T (и в этом Go asm). Как ни странно, кажется, что Go всегда использует AX, а не EAX или RAX, даже с 32-битным размером операнда. MI не имеет для меня никакого смысла (поскольку я не знаю Go asm), но LM и MI не являются допустимыми кодами состояния. felixcloutier.com/x86/CMOVcc.html   -  person Peter Cordes    schedule 09.12.2016
comment
@PeterCordes Я предполагаю, что суффикс L означает «длинный», как и другие инструкции, а суффикс MI означает «минус».   -  person Ross Ridge    schedule 09.12.2016
comment
Какой смысл в еще одном синтаксисе сборки x86? Любая веская причина?   -  person Ped7g    schedule 09.12.2016
comment
@ Ped7g Go изобрел собственный синтаксис сборки, который они используют на всех платформах. Предположительно, это было сделано для того, чтобы упростить написание компилятора, хотя и за счет необходимости переноса ассемблера.   -  person Ross Ridge    schedule 09.12.2016
comment
@RossRidge Но уже есть один общий синтаксис сборки почти для всех платформ ... C ++. Для меня это не имеет никакого смысла. Как бы то ни было, это их проблемы.   -  person Ped7g    schedule 09.12.2016
comment
@Ped7g видео Роб Пайк - Дизайн Go Assembler объясняет некоторые мотивы за синтаксисом ассемблера   -  person Mark    schedule 12.12.2016
comment
@ Марк, хм, поэтому они отупили C, чтобы создать ложное ощущение того, что они находятся на уровне машинного кода. Может хорошо работать для своих нужд, но претензии на универсальную сборку просто смехотворны, разница, например, между x86 и MIPS намного больше, чем синтаксис add. На x86 у вас есть, например, богатая функциональность регистра флагов (нет на MIPS). Они могут выглядеть одинаково, если сравнить вывод C++, потому что C++ никогда полностью не использовал ЦП. Единственное, что они могут быстрее создавать псевдоассемблер новой архитектуры. Но если вы хотите полностью использовать этот процессор, вам все равно понадобится правильный ассемблер позже.   -  person Ped7g    schedule 13.12.2016


Ответы (1)


Ассемблеры Go являются производными от Планировать 9 ассемблеров с небольшими изменениями. Концепция дизайна ассемблеров Plan 9 заключается в том, что они должны были иметь общий синтаксис и соглашения об именах для всех архитектур. Хотя ассемблерный код становится более согласованным в рамках цепочки инструментов Go, иногда чтение такого ассемблерного кода может быть очень запутанным для людей, более знакомых с обычными ассемблерами.

Что касается рассматриваемой инструкции, CMOVLMI BX, DX, в частности; он демонстрирует некоторые специфические варианты дизайна ассемблера Go. Мнемоника CMOVLMI должна читаться как мнемоника ARM, где CMOV — код операции, L — размер операнда (длинное слово, 32 бита), а MI — условие, при котором выполняется операция (minus, т.е. установить флаг знака). Размер операнда соответствует установленным соглашениям DEC, где B, W, L, Q и O обозначают byte, wordord, long. word, quad word и octa word соответственно. Коды состояния соответствуют соглашениям M68k; вот удобная таблица перевода:

Go syntax  Intel syntax
---------  ------------
OS         o
OC         no
CS, LO     b, c, nae
CC, HS     nb, nc, ae
EQ         e, z
NE         ne, nz
LS         be, na
HI         nbe, a
MI         s
PL         ns
PS         p, pe
PC         np, po
LT         l, nge
GE         nl, ge
LE         le, ng
GT         nle, g

Мнемоники LO и HS меняются местами для целей, где перенос является обратным заимствованию, например ARM. Для инструкций перехода варианты синтаксиса Intel распознаются как альтернативные мнемоники для облегчения перехода. Однако это не относится к другим инструкциям.

Кроме того, ассемблер Go не различает размеры регистров общего назначения по разным именам регистров разных размеров (за исключением AL, BL, CL и DL, поддерживаемых для совместимости с AH, BH, CH и DH). Регистр BX может относиться к любому из bl, bx, ebx и rbx в зависимости от размера операнда инструкции.

Наконец, порядок операндов соответствует соглашениям AT&T, т. е. источник, затем пункт назначения.

Таким образом, инструкция соответствует инструкции Intel.

cmovs edx, ebx

Для сравнения различных представлений утилита objdump, поставляемая с набором инструментов Go, поддерживает флаг -gnu. Это выводит инструкции в синтаксисе GNU в дополнение к синтаксису Plan 9, что упрощает их сравнение.

person fuz    schedule 30.10.2020