考虑汇编代码-mov edi, offset newarray
根据我所读到的内容,这将把newarray
的地址放入寄存器edi
我不明白的是这个术语offset
这个术语的英文含义如何适应这里
。
x86内存地址的形式为segment:offset
,其中偏移部分位于像EDI(或64位代码中的RDI(这样的普通(通用(寄存器中。
在我们使用平面内存模型的现代系统中,segment
的基数始终为0,而offset
是整个地址,等于线性地址。
用于mov eax, [rdi + rax*4 + 1234]
:的x86-64寻址
-
RDI是寻址模式下的基寄存器。
- RAX是索引(因为它具有比例因子,或
[rdi+rax]
中的第二个寄存器( - 1234是位移,编码为扩展到64位的双字(disp32(符号
- RAX是索引(因为它具有比例因子,或
-
RDI + RAX*4 + 1234
是通过该寻址模式计算出的有效地址。(因此,即使FS段基数为非零,lea eax, fs:[rdi + rax*4 + 1234]
也会给您这个值。(这是seg:off地址的偏移部分。 -
作为基寄存器的RDI表示DS段。
seg:off
->线性地址为DS_base + offset
。(这等于偏移量,因为CS、DS、ES和SS基在64位模式中固定为0,而在32位模式中,主流操作系统将其设置为0。( -
线性地址是虚拟地址,因为64位模式要求启用分页。
-
virt->phys转换是通过在TLB缓存的页表中查找页码部分(底部12上方的位(来进行的。(为什么在x86-64中,虚拟地址比物理地址短4位(48位对52位(?(。生成的物理地址用于访问内存(通过高速缓存(,或者如果物理地址是设备地址,则用于通过PCIe访问MMIO。
所以,是的,要对数组进行索引,您需要MASM语法中的RDI=OFFSET my_array
。(当然,在64位模式下,你会想要像lea rdi, [my_array]
这样的RIP相关LEA,但在32位模式下是的,你会选择mov edi, OFFSET my_array
。(
OS负责确保CS、DS、ES和SS的段基址为0
,因此当EBX=EBP时,[ebx]
和[ebp]
访问相同的线性地址。(通过使用EBX或EBP作为寻址模式的基寄存器而隐含的DS与SS段。(
call ebx
将从与mov dword ptr [ebx], 0C3909090
(3xnop+ret(可以读取或写入的相同内存地址获取代码。
传统的16位实模式代码通常需要确保DS段基础设置为与数据段的开始匹配或大型程序中的数据段。**(在实际模式中,mov ds, ax
写入段寄存器会将基址设置为value<<4
,而不是将该值用作索引GDT或LDT的选择器。(
例如,DOS.exe
程序通常以启动
PROC main
mov ax, @data ; segment for the data section
mov ds, ax
mov es, ax
mov bx, OFFSET other_var
mov ax, [bx] ; relies on DS being set properly
mov [some_var], ax ; also relies on DS; uses the offset of some_var in the addressing mode.
...
您可以在设置DS之前mov bx, OFFSET some_var
,然后取消引用它。线段和偏移零件是独立的。
类似地,传统BIOS MBR引导加载程序需要将DS设置为与它们假定的org
值相匹配,否则它们访问内存中的错误位置。
数据量超过64k的真实模式程序需要多个段,并且必须切换DS或ES才能使用它们。与任何代码都可以有效使用的通用32位指针相比,这通常是不方便的,而且x86-16已经完全过时了,所以人们很少编写真正使用x86分段的新程序。如果您需要大量内存,那么编写32位或64位代码会容易得多。