将 16 位复制到内存位置

Posted

技术标签:

【中文标题】将 16 位复制到内存位置【英文标题】:Copying 16 bit to to memory location 【发布时间】:2019-10-15 02:45:15 【问题描述】:

我现在在大学学习机器架构课程,我们开始学习组装。我们有一个问题说:

下面的 x86-64 汇编指令会将 16 位从 A 寄存器复制到 B 寄存器指向的主内存位置。

我的实验室伙伴认为答案是movw %ax, (%rbx)。 因为我们复制它的地方是一个指针。

我认为是:movw %ax, (%bx) 因为这意味着它的 16 位。

任何解释都会有所帮助,因为我们迷路了,而且没有大量关于此的明确信息!

【问题讨论】:

请注意,您可以查看 void foo(short *p) *p = 1; 的 C 编译器输出,以了解存储到 16 位内存位置的情况。 相关:Moving two bytes into the lowest portion of a register 似乎与同一实验室的不同部分有关。 What does this x86-64 assembly code mean/do? 也是如此 【参考方案1】:

16 位地址大小不适用于 64 位代码。指针是 64 位的。您可以尝试组装movw %ax, (%bx),尽管生成的错误消息foo.s:1: Error: `(%bx)' is not a valid base/index expression 不是很有帮助。 (我使用gcc -c foo.s 在我的 x86-64 Linux 桌面上运行 GAS。)

地址大小和操作数大小是分开的。

mov %ax, (%rbx) 是一个 16 位存储到 RBX 指向的内存。 %ax 是一个 16 位寄存器,因此它意味着 16 位操作数大小。 (是的,在助记符上带有操作数大小覆盖后缀的movw 也是一种有效的书写方式。)


有趣的事实: mov %ax, (%ebx) 在 64 位模式下是可编码的,但它只会使用 RBX 的低 32 位作为内存操作数的地址。您基本上不想在 64 位模式下使用 32 位地址大小,即使在 LEA 指令中也是如此。

你的实验室伙伴是正确的,它完全类似于C:

  uint16_t *p;
  sizeof(p) == 8        // With a normal x86-64 C compiler
  sizeof(*p) == 2

在寻址模式下,您始终必须使用寄存器的全部大小。使用指针的低 16 位作为寻址方式是没有用的。

这方面没有大量明确的信息!

英特尔的手册非常明确,但也很长。 https://software.intel.com/en-us/articles/intel-sdm#three-volume

第 2 卷手册主要部分的 html 摘录(不包括如何阅读部分):https://www.felixcloutier.com/x86/index.html,mov 的条目为 https://www.felixcloutier.com/x86/mov

另请参阅https://***.com/tags/x86/info 上的其他链接。

相关:

data movement error clarification 解释说(几乎)所有 x86 指令都要求其所有操作数的大小相同。举一些例子。 Is this piece of assembly code invalid? 显示尝试使用 (%bl) 作为寻址模式。 Why operand must have size in one line but not the other in x86 assembly 何时/为什么需要明确指定操作数大小,例如 mov $0, (%rbx) 不会汇编,但 movw $0, (%rbx) 会。

【讨论】:

以上是关于将 16 位复制到内存位置的主要内容,如果未能解决你的问题,请参考以下文章

将任意位置的 N 位从一个 int 复制到另一个 int 的算法

将 n 位从 8 位数组复制到 64 位整数?

将例程的内容复制到内存中的另一个位置

将 jar 文件复制到不同的位置

malloc 是保留空间还是只是将指针返回到起始位置? [复制]

在 C++ 中将最低有效位从 int 复制到 long