16位端口地址的32位分配

时间:2015-02-03 00:00:21

标签: assembly io x86

当我在挖掘原始的Xbox内核代码时,我注意到有时当它为端口I / O设置寄存器时,它会为edx分配一个32位值,即使inout指令仅将edx的低16位用作端口地址。举个例子:

mov     edx, 0FFFF8004h
in      ax, dx
or      ax, 1
out     dx, ax
add     edx, 1Eh
in      ax, dx
or      ax, 2
out     dx, ax
mov     edx, 0FFFF8002h
...

在其他地方(例如SMBus读写),它不一致;有时它会将16位值分配给dx,有时将32位值分配给edx

如果从不使用高16位,那么为它们指定非零位是什么意思?

1 个答案:

答案 0 :(得分:2)

我的猜测是作为微优化完成,以避免不存在的危险和/或不显着的性能损失。

例如,程序员最初可能写了类似的东西:

66| BA 8004     mov     dx, 8004h
66| ED          in      ax, dx
66| 83 C8 01    or      ax, 1
66| EF          out     dx, ax
66| 83 C2 1E    add     dx, 1Eh

然后他决定用add dx替换add edx以保存字节并消除解码操作数大小前缀的性能损失:

66| BA 8004     mov     dx, 8004h
66| ED          in      ax, dx
66| 83 C8 01    or      ax, 1
66| EF          out     dx, ax
83 C2 1E        add     edx, 1Eh

然后他在当代的英特尔优化手册中读到了这一点:

  

因为Pentium II和Pentium III处理器可以执行代码   顺序,指令不需要立即相邻的摊位   发生。例2-7还包含部分停顿。

     

示例2-7 Pentium II和Pentium III处理器的部分寄存器停顿

MOV AL, 8
MOV EDX, 0x40
MOV EDI, new_value
ADD EDX, EAX        ; Partial stall accessing EAX

他自己的代码现在看起来很相似,因此他通过将16位MOV指令替换为您在示例中看到的32位指令来避免部分寄存器停顿。 (实际上,我认为ADD指令不会停止,INOUT指令应该给MOV指令足够的时间退休。)

是的,这些微观优化将毫无意义。即使它们确实节省了一两个CPU周期,与执行I / O指令所需的时间相比,性能增益也是微不足道的。但看到微软员工这样做并不奇怪。我在微软代码中看到了比这更糟糕的东西,至少在90年代他们似乎对微优化非常着迷。

您看到的不一致也不足为奇。微软本可以让许多不同的程序员在Xbox内核上工作,并且可以轻松地从Windows或其他项目中包含代码。