2

我正在阅读 Go 源代码,就像一个人一样,当我阅读fastrand()函数时,我的机器将在asm_amd64.s文件中,我遇到了这个片段:

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

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

CMOVLMI 在哪里定义?Go 的内部汇编器是独一无二的吗?

4

1 回答 1

5

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

至于有问题的指令CMOVLMI BX, DX,具体来说;它展示了 Go 汇编器的一些特殊设计选择。助记符CMOVLMI必须像 ARM 助记符一样阅读,其中CMOV是操作,L是操作数大小(长字,32 位),MI是执行它的条件(减号,即符号标志集)。操作数大小遵循已建立的 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

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

此外,Go 汇编器不会通过给不同的寄存器大小不同的名称来区分通用寄存器大小(除了AL, BL, CL, 并且DL支持与AH, BH,CH和保持一致DH)。寄存器BX可以引用 、 、 和 中的任何一个blbx具体ebx取决于rbx指令的操作数大小。

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

因此,该指令对应于 Intel 指令

cmovs edx, ebx

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

于 2020-10-30T16:00:40.540 回答