x86 汇编/MMX
MMX 是英特尔于 1996 年推出的补充指令集。大多数新指令都是“单指令,多数据”(SIMD),这意味着单个指令可以并行处理多个数据。
然而,MMX 存在一些问题:指令执行速度略低于常规算术指令,使用 MMX 寄存器时无法使用浮点单元 (FPU),并且 MMX 寄存器使用饱和算术。
在 8 位灰度图像中,255 是纯白色的值,0 是纯黑色的值。在常规寄存器 (AX、BX、CX ...) 中,如果我们将白色加 1,我们得到黑色!这是因为常规寄存器“回绕”到下一个值。MMX 寄存器通过一种称为“饱和算术”的技术来解决这个问题。在饱和算术中,寄存器的值永远不会再次回绕到 0。这意味着在 MMX 世界中,我们有以下等式
255 + 100 = 255 200 + 100 = 255 0 - 100 = 0; 99 - 100 = 0;
对于习惯于寄存器回绕的人来说,这可能在开始时看起来违反直觉,但在某些情况下是有意义的:如果我们试图使白色更亮,它不应该变成黑色。
MMX 寄存器宽 64 位,但可以分解如下
2 32 bit values 4 16 bit values 8 8 bit values
MMX 寄存器不能轻松地用于 64 位算术。假设我们在 MMX 寄存器中加载了 4 个字节:10、25、128、255。我们将它们排列如下
MM0: | 10 | 25 | 128 | 255 |
我们执行以下伪代码操作
MM0 + 10
我们会得到以下结果
MM0: | 10+10 | 25+10 | 128+10 | 255+10 | = | 20 | 35 | 138 | 255 |
请记住,我们的算术在最后一个框中“饱和”,因此值不会超过 255。
使用 MMX,我们实质上是在使用常规寄存器执行 1 次加法所需的时间内执行了 4 次加法,使用了少 4 倍的指令。
有 8 个 64 位 MMX 寄存器。为了避免添加新的寄存器,它们被设置为与 FPU 堆栈寄存器重叠。这意味着MMX 指令和 FPU 指令不能同时使用。MMX 寄存器直接寻址,不需要像 FPU 寄存器那样通过入栈和出栈来访问。
MM7 MM6 MM5 MM4 MM3 MM2 MM1 MM0
这些寄存器对应于 FPU 堆栈上相同编号的 FPU 寄存器。
通常,当您在代码中启动包含 MMX 指令的汇编块时,CPU 会自动禁止浮点指令。要重新允许 FPU 操作,您必须使用 emms
结束所有 MMX 代码。
以下是用 GNU AS 和 GCC 编写的程序,它将 8 个字节从一个变量复制到另一个变量,并打印结果。
汇编部分
.globl copy_memory8
.type copy_memory8, @function
copy_memory8:
pushl %ebp
mov %esp, %ebp
mov 8(%ebp), %eax
movq (%eax), %mm0
mov 12(%ebp), %eax
movq %mm0, (%eax)
popl %ebp
emms
ret
.size copy_memory8,.-copy_memory8
C 部分
#include <stdio.h>
void copy_memory8(void * a, void * b);
int main () {
long long b = 0x0fffffff00000000;
long long c = 0x00000000ffffffff;
printf("%lld == %lld\n", b, c);
copy_memory8(&b, &c);
printf("%lld == %lld\n", b, c);
return 0;
}
使用几个后缀来指示指令操作的数据大小
- Byte(8 位)
- Word(16 位)
- Double word(32 位)
- Quad word(64 位)
操作的有符号性也由后缀表示:US 表示无符号,S 表示有符号。
例如,PSUBUSB 减去无符号字节,而 PSUBSD 减去有符号双字。
MMX 定义了超过 40 个新的指令,列在下面。
EMMS、MOVD、MOVQ、PACKSSDW、PACKSSWB、PACKUSWB、PADDB、PADDD、PADDSB、PADDSW、PADDUSB、PADDUSW、PADDW、PAND、PANDN、PCMPEQB、PCMPEQD、PCMPEQW、PCMPGTB、PCMPGTD、PCMPGTW、PMADDWD、PMULHW、PMULLW、POR、PSLLD、PSLLQ、PSLLW、PSRAD、PSRAW、PSRLD、PSRLQ、PSRLW、PSUBB、PSUBD、PSUBSB、PSUBSW、PSUBUSB、PSUBUSW、PSUBW、PUNPCKHBW、PUNPCKHDQ、PUNPCKHWD、PUNPCKLBW、PUNPCKLDQ、PUNPCKLWD、PXOR