数组的偏移量是如何表示数组的起始地址的



考虑汇编代码-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(符号
  • 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位代码会容易得多。

相关内容

  • 没有找到相关文章

最新更新