Assembly 将1字节立即数值添加到2字节内存位置

Assembly 将1字节立即数值添加到2字节内存位置,assembly,x86,nasm,Assembly,X86,Nasm,来自的添加说明文档说明如下: 请注意我突出显示的两个说明 我在NASM中尝试了以下代码(符合第一条突出显示的指令): 但我得到了以下错误: 警告:有符号字节值超出界限 我做错了什么?8位立即数操作数(这里用imm8表示)被符号扩展为16(或32)位,以匹配其他操作数的大小(r/m16或r/m32) 因此,只能表示-128和127之间的值,这就是为什么您会收到来自汇编程序的此警告 对于值0xA5,需要使用WORDimmediate(imm16): (虽然源操作数上的字是可选的,因为它由常量的大小

来自的
添加
说明文档说明如下:

请注意我突出显示的两个说明

我在NASM中尝试了以下代码(符合第一条突出显示的指令):

但我得到了以下错误:

警告:有符号字节值超出界限


我做错了什么?

8位立即数操作数(这里用
imm8
表示)被符号扩展为16(或32)位,以匹配其他操作数的大小(
r/m16
r/m32

因此,只能表示-128和127之间的值,这就是为什么您会收到来自汇编程序的此警告

对于值0xA5,需要使用
WORD
immediate(
imm16
):


(虽然源操作数上的
字是可选的,因为它由常量的大小暗示)。

我不会重复@fuz的答案,但我想补充:

如果您只是让汇编程序通过编写
add word[myvar],0xA5
来完成它的工作,它就会选择最小的编码。如果您的立即数适合符号扩展imm8,它将使用
addr/m16,imm8
编码。通常不需要对非内存操作数使用大小重写。所有主要的x86汇编程序都优化了立即操作数的大小。一些(例如NASM)甚至会将
mov-rax,1
优化为等效但较短的
mov-eax,1
,以及类似的东西,但其他(YASM)不会

不过,您可以强制汇编器使用比填充/对齐所需范围更广的直接指令。e、 g.
添加单词[myvar],严格单词1
。将使用
imm16
版本。(如果没有
strict
,它不会阻止汇编程序将其优化为更小的编码。)您还可以
添加字[rcx+strict dword 0],strict字1
以强制对寻址模式进行
[base+disp32]
编码


如果可能,避免将16位立即操作数写入指令,而不是
mov
。在许多英特尔CPU上,由于内存不足,该指令的解码速度会很慢。在具有解码uop缓存的较新CPU上,这可能不是问题。但在较旧的英特尔CPU上,这可能会运行得更快,但代价是使用暂存器:

movzx  eax, word [myvar]
add    eax, 0xA5          # add ax, 0xa5 is 1B smaller, but has the same LCP stall.
mov    [myvar], ax
add
/
sub
从左到右进位,因此较宽add的较低部分始终与较窄的
add
相同。避免寄存器操作数的LCP暂停通常很便宜(对于
add eax,imm32
,只需要额外的1B,因为它不需要操作数大小前缀),但加载和存储是额外的


这是一个更大的代码大小,所以在没有LCP暂停的CPU上可能会更慢。对于Intel Sandybridge系列的前端(它可以在一个指令版本中微融合load+add),只需增加1个uop,对于执行单元/调度程序,uop的数量相同。(内存目标指令解码以加载、ALU和存储UOP。)

如果您尝试使用-91而不是0xA5,或者您正在尝试添加+165怎么办?@old_timer
add WORD[myvar],BYTE-91
起作用,但是
add WORD[myvar],BYTE 165不起作用。
您想做的是-91还是+165?如果是+165,那么fuz回答了您的问题,并且已经说过字节165不起作用。但是,如果您没有尝试+165而不是-91,那么请使用-91而不是0xA5,fuz只能部分回答您的问题。几乎总是最好让汇编程序为您选择立即数的宽度,并在出现歧义时将操作数大小说明符放在内存操作数上。(另一个选项是
mov eax,0xa5
/
add[myvar],ax
,但在现代Intel上,后端的UOP更多,前端的UOP总数相同:(1+2=3)。内存dst add的加载+添加微保险丝,存储地址+存储数据uops微保险丝,所以
add[mem],reg
是2个前端UOP总计,4个后端UOP。(与movzx加载相同的后端UOP总计;添加reg,imm;mov存储;不包括mov立即数。)
add WORD [myvar], WORD 0xA5
movzx  eax, word [myvar]
add    eax, 0xA5          # add ax, 0xa5 is 1B smaller, but has the same LCP stall.
mov    [myvar], ax