【问题标题】:Weird data sizes?奇怪的数据大小?
【发布时间】:2015-12-09 11:41:34
【问题描述】:
1 Byte = 8bits
1 Halfword = 16bits = 2 Bytes
1 Word = 32 bits = 4 Bytes
1 Long = 64 bits = 8 Bytes

但是在 x86 汇编(AT&T 语法)中,我使用 movw(移动字)将半字移动到 16 位寄存器,使用 movl(移动长)将字移动到 32 位寄存器。我在运行 32 位操作系统的 64 位操作系统上使用虚拟机。

我做错了什么?

这是否意味着在我的 VM 中运行的操作系统中,大小为:

1 Byte = 4bits
1 Halfword = 8bits = 2 Bytes
1 Word = 16 bits = 4 Bytes
1 Long = 32 bits = 8 Bytes

我检查了 GDB 的大小,我认为它们是:

1 Byte = 8bits
1 Halfword = 16bits = 2 Bytes
1 Word = 32 bits = 4 Bytes
1 Long = 64 bits = 8 Bytes 

【问题讨论】:

标签: assembly x86 gdb word att


【解决方案1】:

术语字长或machine word,通常是指寄存器的大小,以及本机加载/存储的大小。维基百科文章提到了我在这个答案中写的一些相同的东西。

对于 64 位系统,一个字可能意味着 8 个字节,但是对于 64 位 RISC 机器来说,通常使用字 = 32 位。它们中的大多数都是从 32 位 RISC ISA 演变而来的,因此保持相同的术语并将 64 位称为双字是很自然的。

(请注意,GDB 使用自己的“词”概念,与 ISA 不同。)


但是 x86 是从 16 位 8086 演变而来的,其中 word = 16 位。当 x86 扩展为具有 32 位模式 (i386) 时,每个人最简单的选择就是为所有内容保持相同的名称。 x86 dword 仍然是 32 位,x86 字仍然是 16 位。即使是原始的 8086 + 8087 也可以加载和存储 dword 和 qword 整数、浮点数和双精度数,并且 8086 中存在像 cwd(符号扩展字到 dword)这样的指令来设置 idiv,所以这些术语已经完整在 386 之前使用将寄存器宽度扩展到 dword。

还请注意,重命名所有内容会非常混乱,因为当 386 是新的时,它们中的大多数仍然在 16 位模式下用于运行 DOS 程序。即使是现代 x86-64 CPU 也完全支持在 16 位实模式下运行,因此在英特尔手册的不同部分中使用 word 表示不同的含义会非常令人困惑。

字节总是是一个 8 位的八位字节,除了在某些历史计算机体系结构中。有些是 9 位字节。 C 标准仍然不要求 CHAR_BIT = 8,因此要编写完全可移植的代码,您不能假设或 2 的补码有符号整数。

所以在 x86 文档和 asm 助记符/语法中:

  • B = 字节 = 8 位(PADDB 在向量中添加压缩的 8 位整数)
  • W = word = 16 位(PADDW 在向量中添加压缩的 16 位整数)
  • D = long 或 dword(双字)= 32 位(PADDD 在向量中添加压缩的 32 位整数)
  • Q = 四字 = 64 位(PADDQ 在向量中添加压缩的 64 位整数)
  • DQ = 双四进制(有时也是八字)= 128b(movdqa 复制对齐的 128b。PUNPCKLQDQ:交错 L两个 64 位 Q 128b src 和 dest 的词放入 DQ dest。)

AVX movdqa ymm0, [rdi] 是一个 32B 负载,尽管它仍然使用相同的助记符。 AVX 更像是多个 128b 通道,而不是真正的原生 256b 向量,所以这种说法是合理的。

在 NASM 语法中,有时需要像 mov ax, word ptr [rdi] 这样的语法来指定操作数大小,而不是从 dest 寄存器推断它。 AT&T 语法在助记符上使用后缀来指定操作数大小,如果您不想让它隐含并从寄存器的选择中推断:movw (%rdi), %ax

助记符中的 B/W/D 事物早于向量扩展,以字符串移动指令为例。 STOS 确实 *(rdi+=size) = al/ax/eax/rax。它可以用一个操作数编写,例如
STOS byte pointer [RDI] 告诉汇编器要编码的操作数大小版本。但即使是 Intel / MASM / NASM 语法,你也可以写STOSB / STOSW / STOSD / STOSQ


x86 非常不是面向单词的架构。

“机器字”的整个概念不适用于 x86。 仅限 32 位的 P5 Pentium CPU 保证高达 64 位的原子加载/存储。 (例如,使用 x87 或 MMX),即使 integer 寄存器宽度仅为 32 位。 (64 位 CAS 在 32 位模式下需要 lock cmpxchg8b)。

使用 x86-64,可以保证对 SSE2 的支持,因此我们有 16 字节的向量寄存器,并且基本上可以有效地支持每条具有 8、16、32 或 64 位操作数大小的整数指令。 (32 位操作数大小是 x86-64 机器代码中的默认值(不需要额外的前缀),因此它对于代码大小和有时还有除此之外的性能是最有效的,例如在某些情况下对于 divimul CPU。)

此外,未对齐的加载和存储是完全有效的,只要不跨越缓存行边界,甚至不需要额外的缓存 RMW 周期来将未对齐或字节存储提交到 L1d 缓存。而且指令格式是字节流,不是对齐的字。

所以说现代 x86-64 有任何特定的“字长”并不是很有意义。这个概念不适合 x86-64 作为 ISA,当然也不适合具有高效未对齐加载/存储的实际现代微架构。

【讨论】:

    【解决方案2】:

    在 x86 中,一个字总是 16 位:

    1 Byte = 8 bits
    1 Word = 16 bits = 2 Bytes
    1 Dword (long) = 32 bits = 8 Bytes
    1 Qword = 64 bits = 16 Bytes
    

    在 GDB/实际大小(在 32 位计算机上):

    1 Byte = 8bits
    1 Halfword = 16bits = 2 Bytes
    1 Word = 32 bits = 4 Bytes
    1 Giant (long) = 64 bits = 8 Bytes 
    

    由于 16 位处理器,英特尔在字长上“搞砸了”。

    【讨论】:

    • 参见 Peter Cordes 的回答。您的带有半字的“GDB”列表对 Intel 和兼容设备毫无意义。为此,您拥有 16 位、32 位或 64 位处理器并不重要。英特尔没有“搞砸”。我猜你在想机器词。这些在这里不起作用。 BYTE、WORD 等具有固定的含义和大小。
    • 是的,你说得对,我认为 32 位 PC 应该有一个 32 位字来处理所有内容(阅读下面的引文)。我所说的英特尔“搞砸了”的意思是他们选择将其设为 16 位,以便与一些旧处理器兼容,但我想我错了。谢谢你。 “处理器中的大多数寄存器通常是字大小的,在许多(不是全部)架构中,可以在单个操作中进出工作内存的最大数据块是一个字。” - 关于单词​​的维基百科
    • ISTM 您将“机器字”与 WORD 类型混淆了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-15
    • 2018-10-05
    • 1970-01-01
    • 2018-04-01
    相关资源
    最近更新 更多