在x86汇编程序中,假设您有
为什么需要索引和基本指针寻址模式? 据我所知,每个都可以用循环代替。
同样间接模式似乎也不太有用,因为您可以简单地使用直接模式来引用内存地址。首先访问一个寄存器的目的是什么,该寄存器包含一个指向存储器地址的指针?
简而言之,哪些寻址方式确实是必要的?
答案 0 :(得分:6)
虽然理论上“寻址模式”可用于指代操作数类型,但由于它不涉及地址,因此有点令人困惑。英特尔手册使用“寻址模式”来指代内存寻址,我将使用此定义。
在汇编中,操作数可以是:
在x86架构中,“寻址模式”仅适用于最后一类操作数:存储器操作数(地址),并指可用于计算地址的方法。寻址模式可以在单个可配置寻址模式中汇总:
address = REG_base + REG_index*n + offset
REG_base
,REG_index
,n
和offset
都是可配置的,并且都可以省略(但显然至少需要一个)。
address = offset
称为立即,直接或绝对寻址
address = REG_base
称为寄存器间接寻址
address = REG_base + REG_index
称为基数加索引寻址
同样,您可以添加偏移量(offset
)和比例(n
)。
严格来说,您只需要一种模式即可完成所有操作:注册间接寻址(address = REG
)。这样,如果需要访问内存,可以在寄存器中计算所需的任何地址,并使用它来进行访问。
它也可以通过使用内存替换直接寄存器操作数,并通过使用算术构造值来立即操作数。但是,对于实际的指令集,您仍然可以立即操作数来有效地加载地址,如果您不想要仅指针寄存器,则需要注册操作数。
除了间接寄存器之外的所有其他寻址模式都是为了方便起见,它们确实非常方便:
int
)数组而无需额外的寄存器或计算。这些寻址模式不需要CPU的大量计算:只需要添加和移位。考虑到x86可以在每个周期进行乘法,这些操作很简单,但仍然非常方便。
答案 1 :(得分:1)
memory[memory]
(C数组符号)。
计算可能需要立即生效。您可以使用多个寄存器构造任何值。从零(xor eax, eax
),inc
开始得到1,左移它到你想要的任何位置,inc
设置低位,左移,因此,最差2*popcount(N)
指令需要N
进入寄存器。请注意,即时移位计数仍然不可用,因此重复移位一个显而易见的方法(shl eax
,是的,有一个单独的编码用于逐个移位,或者只是使用{{1将仅取决于最高设置位的位置。所以add eax, eax
显然是明显的转变和公司。
绝对(你称之为直接)内存寻址不是最有用的寻址模式。我们可以通过使用一系列指令(参见上文)构建地址并使用log2(N) + popcount(N)
来模拟它。如果我们试图减少,我们想放弃它。正如杰斯特所指出的那样,保持绝对地址作为我们唯一的形式将是非常不方便(或者可能不可能?)使用。
索引显然可用于性能,而非必要性:您可以使用单独的说明进行移位和添加。
位移也只是为了提高性能,所以我们可以摆脱它们并强制代码手动添加任何位移。请参阅立即段落了解如何。
我相信x86仍然可以通过 [register]
和register
寻址模式进行任意编程。
使用[register]
,register
和[register]
,性能应该比完整的x86差很多。
如果对内存的隐式访问不算作寻址模式,您当然可以使用immediate
和[register]
模拟lodsd
,但您不会能够进行原子读 - 修改 - 写操作。但这感觉就像是作弊。
还有堆栈(stosd
):我不知道堆栈+注册机器是否是Turing-complete,但它通常不是可编程的。当然,如果您修改push/pop
,则可以再次模拟e/rsp
,但操作数大小的选择少于[register]
/ lodsb/w/d/q
。
stosb/w/d/q
)的方法,所以在实践中你更像16 16B矢量-register槽用于存储堆栈以外的本地状态。尽管如此,它的尺寸有限,这可能意味着32位386 ISA中的8个GP寄存器与64位AVX2 ISA中的所有整数/ mmx / ymm寄存器相关,这与机器是否正在进行调整无关 - 完成只有推/弹,寄存器,并且除了push / pop之外没有修改堆栈指针。