我正在阅读Go源代码,就像我在阅读fastrand()
函数一样,我的机器将在asm_amd64.s
文件中,我遇到了这个片段:
XORL $0x88888eef, DX
CMOVLMI BX, DX
MOVL DX, m_fastrand(AX)
对于我的生活,我无法弄清楚CMOVLMI
应该做什么。对它的搜索显示只有Go似乎对它有所了解;我可以在AMD X86_64参考中找到大量的CMOVxx
操作码,而Wikipedia Page有很长的条件移动指令历史记录,但这不会出现在该列表的任何位置。
CMOVLMI在哪里定义?它是Go的内部汇编程序的独特之处吗?
答案 0 :(得分:3)
Go assemblers来自Plan 9 assemblers,几乎没有变化。 Plan 9汇编程序的设计概念是,它们应该在所有体系结构中具有通用的语法和命名约定。在使汇编代码在Go工具链的框架内更加一致的同时,有时对于那些更熟悉常规汇编程序的人来说,阅读这样的汇编代码可能会非常混乱。
具体来说,有关指令CMOVLMI BX, DX
;它展示了Go汇编器的一些特殊设计选择。必须像ARM助记符一样读取助记符CMOVLMI
,其中CMOV
是操作码,L
是操作数大小(长字,32位),而MI
是条件在其上执行( mi nus,即设置标志标志)。操作数大小遵循已建立的DEC约定,其中B
,W
,L
,Q
和O
代表 b yte , w ord, l 单词, q uad单词和 o cta单词。条件代码遵循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。对于跳转指令,英特尔语法变体被视为替代助记符,以简化过渡过程。但是,其他说明不是这种情况。
此外,Go汇编器不会通过给不同的寄存器大小指定不同的名称来区分通用寄存器的大小(AL
,BL
,CL
和DL
除外)支持与AH
,BH
,CH
和DH
保持一致。根据指令的操作数大小,寄存器BX
可以引用bl
,bx
,ebx
和rbx
中的任何一个。
最后,操作数的排序遵循AT&T约定,即源,然后是目的地。
该指令因此对应于Intel指令
cmovs edx, ebx
要比较不同的表示形式,Go工具链附带的objdump
实用程序支持-gnu
标志。除了转储Plan 9语法外,它还以GNU语法转储指令,从而可以轻松比较两者。