我正在通过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
在掉头时必须执行的指令.这会增加代码大小并使落空情况变慢.
我建议如果你只是学习汇编语言,那么你不要担心这样的事情,这通常会给你带来边际性能提升.只需编写代码即可使工作正常.在它们工作之后,您可以对它们进行分析,如果您认为在查看配置文件数据后有必要,请调整您的功能.
汇编程序通常不会自动为您执行此操作.
因为(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 个银行)。
希望我很清楚。:)
归档时间: |
|
查看次数: |
9602 次 |
最近记录: |