【问题标题】:How to index arrays properly in x86 assembly如何在 x86 程序集中正确索引数组
【发布时间】:2013-11-18 02:50:11
【问题描述】:

我正在努力确保我了解 SI 和 DI 寄存器。我的汇编语言背景在某种程度上仅限于 6502,所以请耐心等待。

我有一个简单的例子来说明如何使用 SI 作为一个简单的计数器。我有点担心我可能会误用这个寄存器。

mov si, 0   ; set si to 0
mov cx, 5   ; set cx to 5 as we will count down to 1

do:       
   mov ah, 02h          ; setup 02h DOS character output interrupt   
   mov dl, [table + si] ; grab our table with the si offset 
   add dl, '0'          ; convert to ascii integer
   int 21h              ; call DOS service

   inc si               ; increment si
   loop do              ; repeat unto cx = 0
ret

table: db 1,2,3,4,5

---
OUTPUT:> 12345

这是使用 SI 的正确方法吗?我知道在 6502 汇编中,您可以使用 X 和 Y 寄存器来偏移数组/表。然而,在我对 x86 的研究中,我开始意识到还有很多工作要做。比如 'loop' 指令中 CX 是如何自动递减的。

我希望继续前进,我将能够通过编写高效的代码来节省资源。

提前感谢您的意见。

【问题讨论】:

标签: arrays assembly x86 x86-16


【解决方案1】:

您的程序实际上运行良好。在开头添加org $100,我设法用FASM编译它并在DosBox中运行:

【讨论】:

    【解决方案2】:

    SI 的这种用法非常好。 SI 具有在大多数英特尔调用约定中作为保留寄存器的好处。此外,从历史上看,SI 是少数可以在内存加载操作中用作索引的寄存器之一。在现代 Intel CPU 中,任何寄存器都可以。

    SI 仍然可以通过 lods 指令获得一些特殊处理。

    【讨论】:

      【解决方案3】:

      在 6502 上,您有两个变址寄存器(X 和 Y),您可以以不同的方式(直接、间接、间接变址、变址间接......)。

      在 x86 上,您有 4 个寄存器可用作指针寄存器:BX、BP、SI 和 DI(在 32 位模式下,您几乎可以使用所有寄存器)

      BX 和 DI 可以组合(例如:[BX+DI+10])

      BP 通常用于在进入函数时(使用 C 编译器时)存储旧堆栈指针。但是,当您在汇编程序中编程时,没有不会误用寄存器(除非您将堆栈指针用于不同的东西)。你不能做错任何事!

      但要小心:在 x86(16 位模式下)上,您还必须关心段寄存器 - 这是 6502 所没有的!

      这些寄存器是必需的,因为您只能使用 16 位寄存器寻址 64 KiB,但 8086 有 1 MiB 地址空间。为了解决这个问题,地址由一个 16 位段和一个 16 位偏移量组成,因此地址实际上不是 16 位而是 32 位长。前 16 位的确切含义取决于 CPU 的工作模式。

      存在以下段寄存器:

      • CS: CS:IP 是指令指针
      • SS:SS:SP 是堆栈指针;默认用于 SP 和 BP 指针操作
      • DS:默认用于所有其他指针操作(除了 SP 和 BP)
      • ES:附加寄存器
      • FS、GS:自 80386 以来的其他寄存器

      您可以覆盖要使用的默认段寄存器:

      MOV AX,ES:[SI+100] ; Load from ES:SI+100 instead of DS:SI+100
      

      字符串操作(如 movsb)始终访问 DS:SI 和 ES:DI(您不能更改此类操作的段寄存器)。

      【讨论】:

      • “字符串操作(如 movsb)始终访问 DS:SI 和 ES:DI(您不能更改此类操作的段寄存器)。”括号中的注释仅对 es:di 指针是正确的。默认情况下,使用ds:si 的任何字符串操作都允许使用段覆盖前缀覆盖此指针的段。
      【解决方案4】:

      SI 的用法很好。但是您可以在其基址中使用其他几个寄存器(但请注意,与 32 位 x86 不同,16 位 x86 代码限制了支持索引的寄存器集。ModRegR/M 结构控制着这一点。)

      您可能需要考虑在循环之前执行add si, table 并在循环内部执行mov dl, [si]。它使人类阅读循环稍微容易一些,因为其中少了一个变量。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-12-20
        • 1970-01-01
        • 2015-06-15
        • 1970-01-01
        • 2013-10-20
        • 2013-10-09
        • 1970-01-01
        相关资源
        最近更新 更多