Go,x64 汇编和 CMOVLMI:此操作码在哪里描述?

Elf*_*erg 1 x86 assembly x86-64 go eflags

我正在阅读 Go 源代码,正如人们所做的那样,当我阅读该fastrand()函数时(对于我的机器来说该函数将位于文件中asm_amd64.s),我遇到了以下代码片段:

    XORL    $0x88888eef, DX
    CMOVLMI BX, DX
    MOVL    DX, m_fastrand(AX)
Run Code Online (Sandbox Code Playgroud)

对于我的一生,我无法弄清楚CMOVLMI应该做什么。对它的搜索表明,似乎只有 Go 知道它的任何事情;CMOVxx我可以找到AMD X86_64 参考中定义的大量操作码,并且维基百科页面有条件移动指令的悠久历史,但这并没有出现在该列表中的任何位置。

CMOVLMI 在哪里定义的?它是 Go 内部汇编器所独有的吗?

fuz*_*fuz 5

Go 汇编程序源自Plan 9 汇编程序,几乎没有变化。Plan 9 汇编器的设计理念是它们应该在所有体系结构中具有通用的语法和命名约定。虽然使汇编代码在 Go 工具链的框架内更加一致,但对于更熟悉传统汇编器的人来说,阅读此类汇编代码有时会非常混乱。

至于有问题的指令,CMOVLMI BX, DX具体而言;它展示了 Go 汇编器的一些独特的设计选择。助记符CMOVLMI必须像 ARM 助记符一样读取,其中CMOV是操作,L是操作数大小(长字,32 位),MI是执行它的条件(minus,即符号标志设置)。操作数大小遵循既定的 DEC 约定,其中BWLQ和分别O代表字节四字和八字。条件代码遵循 M68k 约定;这是一个方便的翻译表:

Go syntax  Intel syntax  read
---------  ------------  ----
OS         o             Overflow Set
OC         no            Overflow Clear
CS, LO     b, c, nae     Carry Set / LOwer
CC, HS     nb, nc, ae    Carry Clear / Higher or Same
EQ         e, z          EQual
NE         ne, nz        Not Equal
LS         be, na        Lower or Same
HI         nbe, a        Higher
MI         s             MInus
PL         ns            PLus
PS         p, pe         Parity Set
PC         np, po        Parity Clear
LT         l, nge        Less Than
GE         nl, ge        Greater or Equal
LE         le, ng        Less or Equal
GT         nle, g        Greater Than
Run Code Online (Sandbox Code Playgroud)

助记符LOHS被交换为进位与借位相反的目标,例如 ARM。对于跳转指令,英特尔语法变体被识别为替代助记符以简化转换。然而,其他指令的情况并非如此。

此外,Go 汇编器不会通过为不同的寄存器大小提供不同的名称来区分通用寄存器大小(除了ALBLCLDL支持与AHBHCH和 保持一致DH)。寄存器BX可以引用blbxebx、 和中的任何一个,rbx具体取决于指令的操作数大小。

最后,操作数排序遵循 AT&T 约定,即源,然后是目的地。

因此该指令对应于 Intel 指令

cmovs edx, ebx
Run Code Online (Sandbox Code Playgroud)

为了比较不同的表示形式,objdumpGo 工具链附带的实用程序支持一个-gnu标志。除了 Plan 9 语法之外,这还会转储 GNU 语法中的指令,从而可以轻松比较两者。