我知道内存寻址可以用字大小的倍数来完成,因此对于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 $0x41, 0xffffffff(%ebp) ,// refer to ebp-1 for example
所以它指的是1个字节的内存。
所以它指的是一个字节,而不是4个字节的倍数.4个字节的倍数仅用于esp?或者它与每个注册相关?
答案 0 :(得分:2)
4个字节的倍数仅适用于esp?或者它与每个寄存器有关吗?
请注意
sub esp, N
不访问任何内存位置,该用法与内存对齐有关,但指令本身是一个简单的 register-immediate 减法,可以使用任何价值。
出于性能原因,如果读取16位,它们应该是2的地址倍数,32位应该是4的地址倍数。
这称为自然边界对齐。
32位系统只能push
/ pop
16或32位值,如果我们只在sub esp, N
,push
/ {{{{}}等指令中使用4的多个值1}}访问在其自然边界上对齐的数据(注意4是2的倍数)。
也可以使用
等指令直接访问堆栈上的数据 pop
这里的原理是相同的, EBP 是4的倍数(注意它的值是旧的 ESP 值,在减法之前)所以32位数据存储在4的地址倍数(自然对齐)。
字节的自然对齐是...... 1.意思是它们应该是1的地址倍数,即无处不在
这就是mov [ebp-04h], eax
执行mov [ebp-01h], 'A'
的原因。
琐事
<子>
作为拇指规则 IA32e 通用指令可以在每个地址从字节读取/写入qwords。
整个对齐故事主要是出于性能原因,与RISC机器不同,它们无法在结构上访问未对齐的数据。
<子>
最初引入的SSE指令带有快速“对齐”(如mov [ebp-04h], 'A'
)和慢速“未对齐”(如movaps
)版本的同一指令。
<子> 64位系统现在明确要求堆栈的128位对齐,以便更好地执行向量指令(和加宽寄存器)。
<子> CPU在 EFLAGS 寄存器中有一个位 AC ,它允许程序启用或禁用严格的对齐策略(àlaRISC),假设操作系统已启用此功能(在 CR0 中设置 AM )。
<子> 更严格地对齐数据CPU数据总线(无论在现代集成DRAM控制器上的任何定义)都是毫无意义的 这就是为什么新的ABI在128位上对齐,即使CPU可以有512位寄存器。
<子> 可以在Manual 2 (the complete set)上找到每条指令的对齐要求。
答案 1 :(得分:0)
适用于80x86(所有模式);寻址始终以字节粒度完成。
对于所有正常指令(不包括SSE等扩展),CPU不需要对齐,任何对齐仅仅是出于性能原因。