为什么代码应该与x86上的偶数地址边界对齐?

Sco*_*ies 20 assembly

我正在通过Kip Irvine的"x86处理器的汇编语言,第六版"工作,我真的非常喜欢它.

我刚才读到了以下段落中的NOP助记符:

"It [NOP] is sometimes used by compilers and assemblers to align code to 
 even-address boundaries."
Run Code Online (Sandbox Code Playgroud)

给出的例子是:

00000000   66 8B C3   mov ax, bx
00000003   90         nop
00000004   8B D1      mov edx, ecx
Run Code Online (Sandbox Code Playgroud)

然后该书指出:

"x86 processors are designed to load code and data more quickly from even 
 doubleword addresses."
Run Code Online (Sandbox Code Playgroud)

我的问题是:原因是因为对于本书所指的x86处理器(32位),CPU的字大小是32位,因此它可以将NOP中的指令拉入并处理它们走 ?如果是这种情况,我假设一个字长为四字的64位处理器会用一个假设的5字节代码和一个nop来做到这一点?

最后,在我编写代码之后,我是否应该通过NOP进行正确的对齐以优化它,或者编译器(MASM,在我的情况下),为我做这个,正如文本似乎暗示的那样?

谢谢,

斯科特

Jim*_*hel 18

在word(对于8086)或DWORD(80386及更高版本)边界上执行的代码执行得更快,因为处理器获取整个(D)字.因此,如果您的说明未对齐,则加载时会出现停顿.

但是,您不能对每条指令进行双向对齐.好吧,我想你可以,但是那时你会浪费空间而且处理器必须执行NOP指令,这会消除对齐指令的任何性能优势.

实际上,在dword(或其他)边界上对齐代码只有在指令是分支指令的目标时才有用,编译器通常会对齐函数的第一条指令,但不会对齐也可以通过通过.例如:

MyFunction:
    cmp ax, bx
    jnz NotEqual
    ; ... some code here
NotEqual:
    ; ... more stuff here
Run Code Online (Sandbox Code Playgroud)

生成此代码的编译器通常会对齐,MyFunction因为它是一个分支目标(到达call),但它不会对齐,NotEqual因为这样做会插入NOP在掉头时必须执行的指令.这会增加代码大小并使落空情况变慢.

我建议如果你只是学习汇编语言,那么你不要担心这样的事情,这通常会给你带来边际性能提升.只需编写代码即可使工作正常.在它们工作之后,您可以对它们进行分析,如果您认为在查看配置文件数据后有必要,请调整您的功能.

汇编程序通常不会自动为您执行此操作.

  • 感谢您的回复!是的,我同意 - 我现在会坚持基础知识,但忍不住要考虑优化。令人着迷的东西! (2认同)
  • @Scott Davies:在汇编中编程时考虑优化并没有错。您这样做很可能是因为您可能需要一些优化。但请注意,本书中给出的这些优化技巧在大约 25 年前是正确的,但现在已经过时甚至是错误的。您确实不想用 nops 填充指令以使它们保留在现代处理器上的偶数地址上,即使它碰巧在 16 位模式下运行。如果您想阅读一些有趣且确实有用的内容,我强烈推荐 agner.org 上的优化手册 (2认同)

Bla*_*ear 6

因为(16 位)处理器只能在偶数地址处从内存中获取值,由于其特殊的布局:它被分成两个“银行”,每个“银行”各 1 个字节,所以数据总线的一半连接到第一个银行和另一半到另一家银行。现在,假设这些 bank 对齐(如我的图片所示),处理器可以获取同一“行”上的值。

  bank 1   bank 2
+--------+--------+
|  8 bit | 8 bit  |
+--------+--------+
|        |        |
+--------+--------+
| 4      | 5      | <-- the CPU can fetch only values on the same "row"
+--------+--------+
| 2      | 3      |
+--------+--------+
| 0      | 1      |
+--------+--------+
 \      / \      /
  |    |   |    |
  |    |   |    |

 data bus  (to uP)
Run Code Online (Sandbox Code Playgroud)

现在,由于此获取限制,如果 cpu 被迫获取位于奇数地址(假设为 3)上的值,则必须获取 2 和 3 处的值,然后获取 4 和 5 处的值,丢弃值 2 和 5然后加入 4 和 3(你说的是 x86,这是一种小端内存布局)。
这就是为什么在偶数地址上使用代码(和数据!)更好的原因。

PS:在 32 位处理器上,代码和数据应该在可被 4 整除的地址上对齐(因为有 4 个银行)。

希望我很清楚。:)