Assembly-在偏移量为5的寄存器/数组中移动

问题描述 投票:0回答:1

快速提问。此代码将无法编译:

mov eax, dword [rbx+rsi*5]

我不希望这样,因为mov和multiplication是两个不同的CPU操作。可以实现的唯一原因是通过移位。

但是,确实可以编译:

mov eax, dword [lst+rsi*5]

“ lst”为变量数组。当在上下文中使用时,它也会产生输出(因此代码可以编译并运行)。为何起作用的解释是什么?

yasm -Worphan-labels -g dwarf2 -f elf64 NAME.asm -l NAME.lst
assembly x86-64 addressing-mode yasm
1个回答
0
投票

x86寻址模式必须符合格式[base + idx*scale + disp0/8/32]。 (或相对于RIP。)

*scale实际上被编码为2位移位计数,因此它可以是1、2、4或8。请参见A couple of questions about [base + index*scale + disp]Referencing the contents of a memory location. (x86 addressing modes)

这里发生的是您的汇编器分解了[lst + rsi*5]为您输入[lst + rsi + rsi*4](或1 + (1<<0..3)形式的其他比例因子)(其中lst是一个4字节(32位)的绝对地址,其符号扩展为64位。是的,它在Linux non-PIE executables中有效;静态代码+数据正好进入虚拟地址空间的低2GiB这样就可以了。)

但是,如果您已经有了基址寄存器,则无法拆分它,而仍然具有可编码的寻址模式。 [rbx + rsi + rsi*4]是不可能的。

[类似地,NASM和YASM允许您编写类似vaddps xmm0, [rbp]而不是vaddps xmm0, xmm0, [rbp+0]的内容(即使将RBP作为基址寄存器是not encodeable without a displacement。当第一个源操作数与目的地相同时,也将其省略)。例如,写[rbp + rax]而不是[rbp + rax*1]-一种寻址模式每个基址或索引最多只能有1个。

[当您的代码表示的操作明确且可编码时,汇编程序有时会具有便捷的功能,以使源代码看起来与机器代码/您从反汇编中获得的代码有所不同。


移动和乘法是两个不同的CPU操作

寻址模式do包括加法和移位,即使shladd也是分开的指令。那不是原因。同样,imul ecx, [lst + rsi + rsi*4], 12345是有效的指令。用内存源或目标操作数进行的类似移位或加法也是如此。

但是是的,x86寻址模式不能对任意乘法进行编码,只能对2移位计数进行编码。

© www.soinside.com 2019 - 2024. All rights reserved.