是的,asm 具有处理不同格式数据的操作,您可以调用这些类型。但是有零类型安全。这是一种很好的表达方式。
所以 INC 指令“知道”它应该将它正在操作的位解释为整数。
但这是一种笨拙的表达方式。 INC 什么都不“知道”;它只是将操作数提供给 ALU 中的二进制加法器。 完全由程序员(或编译器)在正确的字节上以正确的顺序使用正确的指令来获得所需的结果。例如实现具有类型的高级变量。
每个 asm 指令都按照它在锡上所说的做,不多也不少。指令集参考手册条目中的操作部分记录了它对机器架构状态的全部影响,包括 FLAGS 和可能的异常。例如inc。或者更复杂的指令,带有更有趣的伪代码,显示每个位的存放位置,BMI2 pdep r32a, r32b, r/m32(和图表)。从中提取这些内容的英特尔 PDF 有一个介绍部分,该部分解释了任何符号,例如 CF ← Bit(BitBase, BitOffset); for bts (bit test-and-set)
一切都只是字节(包括指针、浮点数、整数、字符串,甚至像 x86 这样的冯诺依曼架构中的代码)。 (或者在某些东西不是 1 字节的倍数的机器上,一切都只是位。)
没有什么能神奇地为您按类型宽度缩放索引。 (尽管 AVX512 在寻址模式中确实使用了缩放的disp8,因此 8 位位移可以编码高达矢量宽度的 -128..+127 倍,而不是只有那么多字节。在源代码级汇编中,您仍然可以编写字节偏移量,并由汇编器在可能的情况下使用更紧凑的机器代码编码。)
如果您想在指针的低字节上使用inc al 来循环遍历(对齐的)数组的前 256 个字节,那完全可以。 (在 P6 系列以外的 CPU 上效率很高,在读取完整寄存器时会出现部分寄存器停顿。)
在某种程度上,x86 对许多类型具有原生支持。大多数整数指令以字节、字、dword 和 qword 操作数大小 的形式出现。当然还有 FP 指令(float/double/long double),甚至还有大部分已经过时的 BCD 指令。
如果您关心有符号和无符号溢出,请分别查看 OF 或 CF。 (因此,有符号整数与无符号整数的区别在于,对于大多数指令,您在事后查看哪些标志,因为加/减对于无符号和 2 的补码来说是相同的二进制操作)。
但加宽乘法和除法确实有有符号和无符号版本。单操作数 imul 与 mul(和 BMI2 mulx)进行有符号或无符号 N x N => 2N 位乘法。 (但通常您不需要高半结果,可以简单地使用更有效的imul r32, r/m32(或其他操作数大小)。乘法的低半部分与输入的有符号或无符号解释的二进制操作数相同; 只有高半部分不同,具体取决于输入的 MSB 是正位值还是负位值。)
使用与您正在实现的 C++ 数据类型相同的操作数大小并不总是一个好主意。例如8 位和 16 位通常可以使用 32 位操作数大小来计算,从而避免任何部分寄存器问题。对于加法/减法,进位仅从 LSB 传播到 MSB,因此您可以进行 32 位操作并且只使用结果的低 8 位。 (除非您需要右移或其他操作。)当然,cmp 的 8 位操作数大小会很方便,但这不会写入任何 8 位寄存器。
x86 数据类型/格式不仅仅包括整数
另请参阅How to read the Intel Opcode notation,了解英特尔指令集参考手册中使用的所有符号列表。例如r/m8 是一个 8 位整数寄存器或内存位置。 imm8 是 8 位立即数。 (如果操作数大小大于 8,则通常符号扩展为操作数大小。)
手册将 m32fp 用于 x87 FP 内存操作数,而 m32int 用于 x87 fild / fistp(整数加载/存储)和其他整数-源 x87 指令,如 fiadd。
还有诸如 m16:64 之类的东西,内存中的远指针(segment:offset),例如作为间接远jmp 或远call 的操作数。 计算远指针和 x86 支持的“类型”当然是合理的。 有类似 lgs rdi, [rsi] 的指令从 rsi 指向的 2+8 字节操作数加载 gs:rdi . (当然,更常用于 16 位代码。)
m128 / xmm 可能不是您真正所说的“数据类型”;没有 SIMD 指令实际上将操作数视为 128 位或 512 位整数。 64 位元素是除了随机播放之外的最大元素。 (或纯按位运算,但实际上是 128 个独立的并行与运算,相邻位之间根本没有交互。)