【问题标题】:NASM and 8-bit memory offset confusionNASM 和 8 位内存偏移混淆
【发布时间】:2018-02-27 05:12:00
【问题描述】:

从英特尔软件开发人员手册(在本文中称为 ISDM)和 x86 Instruction Set Reference(我假设它只是前者的副本),我们知道 mov 指令可以从eax/ax/al 到内存偏移量,反之亦然。

例如,mov moffs8, alal 寄存器的内容移动到某个8 位 内存偏移量moffs8

现在,moffs8 是什么?引用 ISDM (3.1.1.3):

moffs8、moffs16、moffs32、moffs64 — MOV 指令的某些变体使用的字节、字或双字类型的简单内存变量(内存偏移)。实际地址由相对于段基的简单偏移量给出。指令中没有使用 ModR/M 字节。 moffs显示的数字表示它的大小,由指令的address-size属性决定。

我强调了moffs8的类型是byte并且大小为8位的句子。

我是一个汇编初学者,所以,在阅读完这篇文章后,我立即开始使用 NASM 玩弄 mov moffs8, al 指令。这是我写的代码:

; File name: mov_8_bit_al.s
USE32

section .text
    mov BYTE [data], al

section .bss
    data resb 2

这是nasm -f bin mov_8_bit_al.s 产生的(十六进制):

A2 08 00 00 00

我是这样理解的:

  • A2MOV moffs8, AL 的操作码
  • 08 是内存偏移量本身,大小为 1 字节
  • 00 00 00 有点垃圾

看起来08 00 00 00 是内存偏移量,但在这种情况下,它是moffs32,而不是moffs8!因此,CPU 在执行A2 时将只读取一个字节,并将00 视为ADD 指令或其他内容,这不是预期的。

目前,在我看来,NASM 在这里生成了无效的字节码,但我想是我误解了一些东西……也许 NASM 不遵循 IDSM?如果是这样,它的代码将无法在 Intel CPU 上正确执行,所以它应该遵循它!

你能解释一下我哪里错了吗?

【问题讨论】:

    标签: assembly x86 mov


    【解决方案1】:

    moffs后面的大小后缀实际上是指操作数大小,而不是地址本身的大小。这反映了r/m 之后大小后缀的含义。

    手册实际上在注释中是这样说的:

    注意事项:
    * moffs8、moffs16、moffs32 和 moffs64 操作数指定相对于段基数的简单偏移量,其中 8、16、32 和 64 参考数据的大小。指令的地址大小属性决定了偏移量的大小,可以是 16、32 或 64 位。

    【讨论】:

    • 从哪里获得指令的地址大小属性?
    • @ForceBru 它取决于地址大小覆盖前缀的模式和存在
    • 啊,所以,如果我在 32 位模式下运行并且没有 0x67 前缀,地址将占用 4 个字节,对吧?
    • @ForceBru 通常汇编程序员不需要处理内存操作数编码(除非您正在编码大小,例如 256 字节的介绍),NASM 选择指令的最佳(大小)编码,当存在一些歧义时,所以大多数时候你只需编写像mov [some_memory],al 这样的符号源,并且只处理head 中8 位大小的数据,将编码留给汇编程序。如果您正在编码大小,那么检查机器代码并尝试多种代码变体是很常见的,除非您可以记住 ISDM 中的所有内容(我不能:/)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 2012-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多