Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 16位端口地址的32位分配_Assembly_Io_X86 - Fatal编程技术网

Assembly 16位端口地址的32位分配

Assembly 16位端口地址的32位分配,assembly,io,x86,Assembly,Io,X86,当我翻阅原始Xbox内核的代码时,我注意到有时当它为端口I/O设置寄存器时,它会为edx分配一个32位的值,即使in和out指令只使用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 ... 在其他地方(

当我翻阅原始Xbox内核的代码时,我注意到有时当它为端口I/O设置寄存器时,它会为
edx
分配一个32位的值,即使
in
out
指令只使用
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位,那么为它们指定非零位有什么意义呢?

我猜这是作为微优化来完成的,以避免不存在的危险和/或微不足道的性能损失

例如,程序员可能最初编写了如下内容:

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
然后他在当代英特尔优化手册中读到:

因为奔腾II和奔腾III处理器可以执行 订购时,无需将指示直接相邻,便可完成安装 发生。示例2-7还包含一个部分失速

示例2-7奔腾II和奔腾III处理器的部分寄存器暂停

MOV AL, 8
MOV EDX, 0x40
MOV EDI, new_value
ADD EDX, EAX        ; Partial stall accessing EAX
他自己的代码现在看起来很相似,因此他通过将16位
MOV
指令替换为您在示例中看到的32位指令来避免部分寄存器暂停。(实际上,我不认为
ADD
指令会暂停,
In
OUT
指令应该给
MOV
指令足够的时间退出。)

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


你所看到的不一致性也不足为奇。微软会有许多不同的程序员在Xbox内核上工作,并且可以很容易地包含来自Windows或其他项目的代码

我在这里推测,但在32位模式下,需要一个操作数大小前缀来将16位立即数移动到寄存器中。解码速度可能会慢一些。更可能的是,程序员使用了整数文本,在平台上默认为有符号32位
int
。如果文本是负数,则可能会产生您看到的代码类型。@EOF我也这么认为,但它们不一致-有时使用16位立即数。此外,由于指令编码,立即数被编码为一个完整的32位整数,即没有符号扩展。这也是我所怀疑的。仍然不确定为什么上面的部分是
0xFFFF
,但我想这并不重要。@Drew这可能是内联汇编吗?编译器可能对16位常量进行了符号扩展。@Drew和Ross:add或
中的操作数大小前缀没有解码惩罚,代码大小除外
add dx,0x1E
使用
imm8
编码,因此操作数大小前缀不会更改insn其余部分的长度。只有ALU操作上的
imm16
操作数才会导致长度更改前缀暂停。哎呀,orig xbox有一个PIII,即使在
mov
指令上,LCP也会暂停,所以如果这段代码的解码速度很重要的话,这就是他们要避免的
add edx,imm8
只保存一个代码字节,除非
in
读取整个注册表并强制合并,否则不会避免部分注册表暂停。@PeterCordes不管这是否是个问题,英特尔奔腾III的优化手册中确实说过“尽可能避免使用前缀指令”我的理论是,应用微优化时没有考虑实际硬件的实际性能优势。例如,他们本可以避免对奔腾更明确的惩罚:“前缀为66h或67h的指令需要一个时钟进行前缀检测,另一个时钟用于长度计算,另一个时钟用于输入FIFO(总共三个时钟周期)。@RossRidge:是的,我得到了你的总体观点。我刚刚指出,最危险的潜在失速可能是16位mov imm上的LCP失速。但关于旧手册的措辞,这是一个很好的观点。你关于盲目遵循优化手册的理论,即使是对于I/O代码,听起来也很有可能。16bit
mov
/32bit
add
和32bit
将最小化代码大小,这是这里的最佳选择。P6部分寄存器暂停比SnB(插入额外uop)更糟糕,但希望即使是如此大量的暂停也不会造成伤害。