assembly - REP INSW 做什么?

标签 assembly io x86 x86-64 nasm

我需要从端口读取一些 16 位值并将它们保存到缓冲区。我正在使用的教程建议使用 REP INSW 指令,但我不知道如何使用它,甚至不知道它是如何工作的......

这条指令相当于两条IN指令吗?

最佳答案

答案就在 Intel® 64 and IA-32 Architectures Software Developer’s Manual第一卷:

Section 18.3 I/O ADDRESS SPACE

Any two consecutive 8-bit ports can be treated as a 16-bit port, and any four consecutive ports can be a 32-bit port. In this manner, the processor can transfer 8, 16, or 32 bits to or from a device in the I/O address space. Like words in memory, 16-bit ports should be aligned to even addresses (0, 2, 4, ...) so that all 16 bits can be transferred in a single bus cycle. Likewise, 32-bit ports should be aligned to addresses that are multiples of four (0, 4, 8, ...). The processor supports data transfers to unaligned ports, but there is a performance penalty because one or more extra bus cycle must be used.

如果您查看第 2A 卷指令集引用中的 INSW 指令文档,它会这样说:

INS/INSB/INSW/INSD — Input from Port to String

INS m16, DX        Input word from I/O port specified in DX into memory location
                   specified in ES:(E)DI or RDI.

INSW 从 IO 端口空间读取 16 位值到指定的内存地址。 INSW 将从 DX 中指定的指定 PORT 开始读取一个字节,并从 PORT+1 读取一个附加字节,这些字节存储在 ES:E(DI) 和 ES 中:分别为E(DI)+1。

为了回答有关 REP INSW 的问题,REP 将按照 E(CX) 中指定的次数重复此过程。 REP INSW 记录为:

REP/REPE/REPZ/REPNE/REPNZ — Repeat String Operation Prefix

REP INS m16, DX    Input (E)CX words from port DX into ES:[(E)DI]

如果您使用REP INSW从端口 0x1F0 E(CX) 读取 16 位数据,那么您实际上会执行以下操作:

  1. 从 0x1F0 和 0x1F1 读取 16 位值,并将其存储到 ES:(E)DI 和 ES:(E)DI+1 指向的内存地址。
  2. 将 E(DI) 加 2。
  3. 将 E(CX) 减 1。
  4. 如果E(CX)不为0,则转至步骤1,否则过程结束。

假设您正在编写 32 位代码,然后从端口 0x1F0/0x1F1 读取 16 位 16 次,您可以在 NASM 中将其编码为:

bits 32
    ; It is assumed that ES is already set and depends on the environment
    mov dx, 0x1f0              ; Read words from port 0x1F0 and 0x1F1
    mov edi, buffer            ; Address of BUFFER
    mov ecx, 16                ; Repeat 16 times
    rep insw

; Other code and data here

; 16 word buffer (total 32 bytes)
buffer: TIMES 16 dw 0x0000

如果编写 16 位代码,它将类似于:

bits 16
    ; It is assumed that ES is already set and depends on the environment
    mov dx, 0x1f0              ; Read words from port 0x1F0 and 0x1F1
    mov di, buffer             ; Address of BUFFER
    mov cx, 16                 ; Repeat 16 times
    rep insw

; Other code and data here

; 16 word buffer (total 32 bytes)
buffer: TIMES 16 dw 0x0000

注释

  • 假设您正在运行的环境中,您具有使用端口 IO 指令的权限级别,并且您具有读/写特定 IO 端口的权限。在实模式下没有任何限制。在保护模式、长模式和 v8086 模式下,您可能有也可能没有使用端口指令或访问特定端口的权限的权限级别。您必须查阅操作系统 (OS) 文档,或者如果您正在编写自己的操作系统,则必须使用权限级别/IOPL/IOPL 位图自行设置权限和端口访问限制。

  • rep insw 还可以使用操作数大小前缀在 64 位模式下使用(NASM 将通过添加 0x66 前缀来处理编码)。计数将以 RCX 为单位,ES 段不适用:

    REP INS r/m32, DX     Input RCX default size from port DX into [RDI].
    

关于assembly - REP INSW 做什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57944636/

相关文章:

c - 如何在汇编中访问结构体的元素?

io - 内存和 IO 带宽之间有什么区别,我们如何测量它们?

c++ - 我们如何在 C++ 中一次从 STDIN 扫描 100 个字节

assembly - 我尝试打印号码时出错

c++ - 在 C++ 中使用 __asm 将 short 类型的变量移动到 EAX(VS 2010)

assembly - x86 示例程序中的段错误

c - 有优化的汇编编译器吗?

c# - 该流不支持seek操作,使用stream

c - 为什么 GDB 和不同的汇编程序给出不同的错误 jmp 地址?

assembly - 计算 DW 数组中等于 1 的元素个数