shi*_*vam 0 x86 assembly terminology masm memory-address
考虑汇编代码 -mov edi, offset newarray
根据我所阅读的内容,这会将 的地址newarray放入寄存器edi
我不明白的是这个术语 这个术语offset的英文含义如何
适合这里。
x86 内存地址的形式为segment:offset,其中偏移部分位于普通(通用)寄存器中,如 EDI(或 64 位代码中的 RDI)。
在我们使用平面内存模型的现代系统中,segment基址始终为 0,并且offset 是整个地址,等于线性地址。
x86-64 寻址mov eax, [rdi + rax*4 + 1234]:
RDI是基址寄存器中的地址模式。
[rdi+rax])RDI + RAX*4 + 1234是该寻址模式计算出的有效地址。(因此lea eax, fs:[rdi + rax*4 + 1234],即使 FS 段基址非零,也会为您提供这一点。)这是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。
所以是的,要索引数组,您需要OFFSET my_arrayMASM 语法中的RDI = 。(当然,在 64 位模式下,您需要一个相对于 RIP 的 LEA,如lea rdi, [my_array],但在 32 位模式下,您会这样做mov edi, OFFSET my_array。)
所述OS需要使得护理确保段基址是0为CS,DS,ES,SS和,所以[ebx]和[ebp]存取同一个线性地址时EBX = EBP。(通过使用 EBX 或 EBP 作为寻址模式的基址寄存器隐含的 DS 与 SS 段。)
这call ebx将从您可以使用mov dword ptr [ebx], 0C3909090 (3x nop + 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.
...
Run Code Online (Sandbox Code Playgroud)
您可以mov bx, OFFSET some_var在设置 DS 之前,并在之后取消引用它。段和偏移部分是独立的。
同样,传统 BIOS MBR 引导加载程序需要设置 DS 以匹配org它们假定的值,否则它们会访问内存中的错误位置。
具有超过 64k 数据的实模式程序需要多个段,并且必须切换 DS 或 ES 才能使用它们。与拥有任何代码都可以有效使用的通用 32 位指针相比,这通常是不方便的,而且 x86-16 已经完全过时了,因此人们很少编写真正使用 x86 分段的新程序。如果您需要大量内存,则编写 32 位或 64 位代码要容易得多。