intel ia 32 上的内存寻址

memory adressing on intel ia 32

我知道内存寻址可以用字长的倍数来完成,所以对于 Intel 32 位,在汇编中分配堆栈上的内存可以用

    //pseudo code
    sub , esp ,4 // so for allocating for a integer on stack
    sub esp, 8 // for a buffer of size 5 for example b[5] 

所以寻址是用 4 的倍数完成的。因此,在堆栈上引用局部变量和参数也是通过

完成的
     // referring to variable --ebp-4

但有时在反汇编中我会看到一些指令,例如

     movb   [=12=]x41, 0xffffffff(%ebp)   ,// refer to ebp-1 for example

所以它指的是1个字节的内存。

所以它指的是一个字节,而不是4的倍数bytes.The4字节的倍数只适用于esp?还是与每个寄存器有关?

对于 80x86(所有模式);寻址总是以字节粒度完成。

对于所有普通指令(不包括 SSE 等扩展),CPU 不需要对齐,任何对齐都只是出于性能原因。

The multiple of 4 bytes is only for esp? or is it related to every register?

注意

sub esp, N

不访问任何内存位置,使用与内存对齐有关,但指令本身是一个简单的register-immediate减法,它可以使用任何值。

出于性能原因,如果您读取 16 位,它们应该在 2 的地址倍数上,32 位应该在 4 的地址倍数上。
这称为自然边界对齐

32 位系统只能 push/pop 16 位或 32 位值,如果我们只在 sub esp, N 这样的指令中使用 4 的倍数,那么 push/ pop 访问在其自然边界上对齐的数据(注意 4 是 2 的倍数)。

堆栈上的数据也可以直接使用

等指令访问

mov [ebp-04h], eax

这里的原理是一样的,EBP是4的倍数(注意它的值是旧的ESP值,之前减法)所以 32 位数据存储在 4 的地址倍数(自然对齐)。

字节的自然对齐方式是... 1。这意味着它们的地址应该是 1 的倍数,即无处不在。
这就是为什么 mov [ebp-01h], 'A' 执行为 mov [ebp-04h], 'A' 的原因。


知识问答

作为 经验法则 IA32e 通用 指令可以 read/write 从每个地址的字节到 qwords。
整个对齐故事主要是出于性能原因,不像 RISC 机器,它们不能在结构上访问未对齐的数据。

当最初引入 SSE 指令时,同一指令带有快速 "aligned"(如 movaps)和慢速 "unaligned"(如 movups)版本。

64 位系统现在明确要求堆栈的 128 位对齐以更好地执行向量指令(和扩展的寄存器)。

CPU 在 EFLAGS 寄存器中有一个位,位 AC,让程序启用或禁用严格对齐策略( à la RISC),假设 OS 启用了此功能(在 CR0 中设置 AM)。

比 CPU 数据总线(对于现代集成 DRAM 控制器上的任何定义)更严格地对齐数据是没有意义的。
这就是为什么新的 ABI 在 128 位上对齐,即使 CPU 可以有 512 位寄存器。

可以在 Manual 2 (the complete set) 上找到每条指令的对齐要求。