如何在x86程序集中正确索引数组

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在x86程序集中正确索引数组相关的知识,希望对你有一定的参考价值。

我试图确保我理解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的研究中,我开始意识到还有更多的工作要做。例如CX如何在'循环'指令中自动递减。

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

提前感谢您的意见。

答案

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

SI仍然得到lods指令的一些特殊待遇。

另一答案

你的程序实际上工作正常。在开头添加org $100,我设法用FASM编译它并在DosBox中运行:

另一答案

在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(您无法更改此类操作的段寄存器)。

另一答案

这是对SI的好用。但是你可以在它的基础上使用其他几个寄存器(虽然要注意,与32位x86不同,16位x86代码限制了支持索引的寄存器集.ModRegR / M结构控制它。)

你可能想考虑在循环之前做一个add si, table并在里面做mov dl, [si]。它使循环更容易让人阅读,因为游戏中的变量少了一个。

以上是关于如何在x86程序集中正确索引数组的主要内容,如果未能解决你的问题,请参考以下文章

如何在 x86 程序集中按值传递结构

如何在 Visual Studio 2017 的 x86 程序集中使用 printf?

如何在 x86(32 位)程序集中将无符号整数转换为浮点数?

在 X86 程序集中访问和移动字节

SQL JSON PATH 如何在从较大的 json 集中提取后按索引访问 json 数组

x86 程序集中的 SSE2 寄存器