寻址通常是基于字节的。唯一地址指向一个字节(可以是字或双字等中的第一个字节,但引用该地址)。
对于任何编号系统,最低有效位保持值基数为 0 次方(数字 1)。次幂为 1 的下一个基数,次幂为 2 的下一个基数。在十进制中,这是个位列,十位列,百位列。在二进制中,二,四......对齐意味着可以被整除,这也意味着最低有效数字为零。
您总是在字节边界上“对齐”,但二进制中的 16 位边界意味着最低有效位为零,32 位对齐两个零,依此类推。
0x1234 在 16 位和 32 位边界上对齐,但不是 64 位
0x1235 未对齐(字节对齐实际上不是问题)
0x1236 在 16 位边界上对齐
0x1230 四个零,因此 16、32、64、128 位不是字节。2,4,8,16 字节。
为什么是出于性能原因,所有存储器都具有固定宽度以及数据总线,一旦实现,您就无法在逻辑中神奇地添加或删除线,存在物理限制,您可以选择不将它们全部用作一部分的设计,但你不能添加任何。
因此,虽然 x86 总线更宽,但假设您有一个 32 位宽的数据总线和一个 32 位宽的内存(想想缓存,还有 dram,但我们一般不直接访问 dram)。
如果我想将 16 位 0xAABB 保存到小端机器中的地址 0x1001,那么 0x1001 将获得 0xBB,0x1002 将获得 0xAA。如果我有一个 32 位数据总线和一个 32 位内存在它的远端,那么如果我为此设计总线,我可以移动这 16 位,通过将 0xXXAABBXX 写入地址 0x1000,字节通道掩码为 0b0110 告诉内存控制器使用与基于 BYTE 的地址 0x1000 相关联的 32 位内存,并且总线上的字节通道掩码告诉控制器只保存中间两个字节,外部两个无关紧要。
内存通常是固定宽度的,因此所有事务必须是全宽度的,它将读取 32 位,用 0xAABB 修改中间的 16 位并将 32 位写回。这当然是低效的。更糟糕的是,将 0xAABB 写入 0x1003,这将是两个总线事务,一个用于地址 0x1000 的 0xBBXXXXXX,另一个用于地址 0x1004 的 0xXXXXXXAA。这在总线上和内存上的读-修改-写都有很多额外的周期。
现在堆栈对齐规则不会阻止写入时的读取-修改-写入。对于发生较大传输的情况,有机会获得性能提升,例如,如果总线是 32 位,而内存是 64 位传输到地址 0x1000,那么基于总线设计,这可能看起来像一个带有长度为二。总线握手发生然后两个背靠背时钟数据移动,而不是握手和一个宽度的数据总线用于较小的传输。因此,如果内存为 32 位宽,那么您将获得收益,那么它是两次写入,而没有读取 - 修改 - 写入缓存中的 sram。很干净,想要避免读取-修改-写入。
随着事情的发展以及硬件和工具需要堆栈对齐,现在这样做一段时间。
根据指令集,很明显你在问 x86,但作为程序员,你有时可以选择将一个字节压入堆栈,然后调整它以对齐它。或者,如果您要为局部变量腾出空间,具体取决于指令集(如果堆栈指针足够通用,可以对其进行数学运算),您可以简单地减去,所以 sub sp,#8 与推两个相同堆栈中的 32 位项目只是为两个 32 位项目腾出空间。
如果规则是 32 位对齐并且您压入一个字节,那么您需要将堆栈指针调整 3 以使堆栈指针的总变化成为 4 个字节(32 位)的倍数。
你怎么知道有多少,你只是简单地数一下。如果它是 16 字节对齐并且您按 4,那么您需要再按 12 或将堆栈指针再调整 12。
这里的关键是,如果每个人都同意保持堆栈对齐,那么您实际上不必查看堆栈指针的低位,您只需在调用其他内容之前跟踪您正在推送和弹出的内容。
如果堆栈与中断处理程序共享(实际上不是在当前运行操作系统的 x86 中,但在通用处理器的许多其他用例中仍然可能并且可能)我还没有看到该规则适用于那里,因为您将看到编译器执行小于对齐大小的推送或弹出,然后使用其他推送或弹出或减法或加法进行调整。如果在这些之间发生中断,则处理程序将看到未对齐的堆栈。
一些架构会在未对齐的访问上出错,这是保持堆栈对齐的另一个原因。
如果您的代码没有弄乱堆栈,那么您不需要弄乱堆栈(指针)。仅当您通过在堆栈上分配空间(堆栈指针上的推送或数学运算)来在代码中使用堆栈时,您才需要关心并且您需要知道您链接此代码并符合的编译器的约定那。如果这都是汇编语言并且没有编译器,那么您自己决定约定,并且基本上在处理器本身的限制范围内做任何您想做的事情。
从您的标题问题来看,它根本与汇编无关,也与机器代码无关。它与您的代码及其功能有关。汇编语言只是一种语言,您可以在其中传达要调整堆栈指针的程度,该指令不关心或不知道任何此类事情,它采用提供的常量并将其用于寄存器。汇编是少数(如果不是唯一)允许您对堆栈指针寄存器进行数学运算的其中之一,因此存在这种联系。但是对齐和组装是不相关的。