使用bx寄存器保存索引可以吗



我在汇编课程中有一项任务要计算字符串中的字数,我需要将答案保存在cx寄存器中。(我在80x86处理器上工作)

所以我设置:

cx到0-这将是我的柜台

bx到0-这将是我的索引

我想知道我是否正确使用它,这是我的代码:

.model small 
.stack 100h
.data
A db '  this   is  a  test  $'
B db 100 dup('$')
.code
mov ax, @data
mov ds, ax
mov cx, 0 
mov bx, 0
looping:
cmp A[bx], ' '
jne foundchar
inc bx
jmp looping

foundchar:
inc bx
cmp A[bx], ' '
je foundword
cmp A[bx], '$'
je soff
jmp foundchar

foundword:
inc cx
inc bx
jmp looping
soff:
.exit
end

我班上的其他人做得不一样,她把si设置为A的偏移。。。我并没有真正理解这个解决方案:

mov cx,0
mov si, offset A
mov dl,0

next2:
inc si
mov dl,[si]
cmp dl,"$"
JE soff
cmp dl, " "
JE test1 ;if the char is space so lets check what is before the char
jmp next2 ; if the char no space jump back to the loop
test1:
mov al,[si-1]
cmp al, ' '
je  next2
add cx,1
jmp next2
soff:
mov al,[si-1]
cmp al,' '
je sofsofi
add cx,1
sofsofi:
.exit
end 

请帮助我理解它,以及什么是更合适的方法来做它。

感谢分配

回答标题中的问题:否。使用BX作为索引是不好的。使用"目标索引"或"源索引"(取决于写入还是读取数据)。使用BX是可行的,但它不被认为是"最佳实践",因为DI和SI的目的是保存索引。

现在的解释是:

尽管(x86)寄存器是命名的,但您可以(当然有某些限制)将它们用于与它们的名称发生冲突的任务,但这可能会导致解释代码时出现错误和问题。

我将尝试在这里为初学者写一个简单的注册指南。

限制:

  • 某些操作从某些寄存器读取数据或将数据写入某些寄存器,例如。MUL使用(E)AX和(E)DX,因此必须确保不存储数据您的程序仍然需要(或PUSH和稍后POP)在寄存器中将对其进行修改
  • 并不是每个寄存器都允许您(直接)访问8位部件
  • 有些寄存器有很酷的专用功能,所以为了不折衷它们你需要正确地使用它们

请记住,下面列出的所有寄存器都可以通过在名称中添加E以扩展(32位)形式使用(例如,EAX是累加器的32位版本,其中较低的16字节包含16位AX)。登记册将按重要性顺序列出(从初学者的角度来看)。

  1. AX-累加器寄存器通常用作主要参数和结果。在更简单的日子里,x86仍然是听说处理器通常有两个参数寄存器,例如。Commodore 64上的X和Y以及用于存储结果的累加器。在里面简而言之,它的名字现在大多是历史性的,而且通常你几乎所有东西都使用的第一个寄存器——例如算术/逻辑运算和DOS(21h)中断通过AH(AX的较高字节)的自变量。除了需要通过AX传递值,您可以将其视为主变量
  2. DX-数据寄存器-这里不需要太多描述,它存储数据。我决定把它列在AX之后,因为这两者是协同工作的很多时候——例如MUL(乘法)使用DX来存储数据从AX溢出。所以,是的,它"只是"次要变量
  3. CX-计数器寄存器-也很简单,它只是另一个通用寄存器。但是这次使用了特别是作为计数器(顾名思义)循环(LOOP族操作数)和字符串指令(REP族操作数)。只要您不使用修改CX的说明你可以自由使用它来做任何你需要的事情(但一定要检查您的数据没有更好的位置)
  4. BX-基址寄存器-长话短说,由于32位到达,该寄存器失去了"偏移"内存地址的目的。所以它是"自由"寄存器,主要用于向后兼容性。可怜的家伙。请使用它,不要让历史迷雾笼罩吞噬这样一个勇敢的小登记册

禁止注册是的,有这样的。

  1. SPBP-堆栈和基指针-默认方法是不直接使用它们,这些由PUSH处理,POP、CALL和RET指令用于管理堆栈,并允许您使用函数。然而,它们可以用于近乎异端的把戏有了黑魔法,你敢亵渎圣栈架吗?更改这些寄存器的值可能会导致实际堆栈溢出。请勿使用除非你真的,真的确定你想要它(并且知道怎么做)。(在某些情况下,BP可以像BX一样成为另一个"自由"寄存器,但现在可以忽略它)

现在开始可怕的寄存器部分,可怕的名称和复杂的操作与它们联系在一起。此外,它们中没有Higher和Lower 8位部分可用(但如果需要,您仍然可以使用位掩码提取它们)。

  1. DISI-目标和源索引-这两个用作指向内存块(缓冲区/数组/字符串)的指针等),用于通过REP操作或其他操作进行自动数据复制/写入基于字符串/数组的。如果你不使用这种混淆操作,则可以使用DI和SI作为数据寄存器无法(轻松)选择更低或更高的限制字节完美选择基于循环的操作
  2. 段寄存器-CS、SS、DS、ES、FS、GS…(eek!现在它是他们的整个军队)-虽然故事可能很长,但简短说明-两个主要部分是代码段和数据段代码段包含代码(令人惊讶,对吧?)您在其中声明正确的数据。段通常与用于复制数据的DI和SI寄存器-例如LODSD期望SI指向数据段中的内存地址,因此简而言之("平面")代码需要首先通知CPU您的数据和代码段就是其中之一。你真的不应该使用那些寄存器,否则分段故障会把你踢进脸

你可以在像这本整洁的指南这样的页面上阅读更多。

至于你的代码,我现在可以给你一些建议(为了彻底修改你的脚本,你需要等到明天或周一,因为我这个周末有点忙)

使用SI/DI更好。在你的代码中,A[bx]相当于(A内存地址)+(SI中的值),CPU是一个非常简单的生物,所以它更喜欢简单的[SI],而不是动态计算。

您自己设置数据段是一件好事,因为它取决于环境(system/cmpu/emulator)来设置初始值。虽然将片段用于专用内容是一个好习惯,但对于这样一个简单的程序,您可以随意在代码段中存储一些数据,它甚至可以通过减少内存跳跃和地址计算来加快执行速度。然后你可以写:MOV AX,CSMOV DS,AX(不能直接做)。保证代码段是包含当前代码的代码段(否则它不会执行)。

调零寄存器可以变得更酷!要在AX中放入0吗?使用XOR AX、AX(AX=AX排他或AX,作为逻辑状态,这将始终导致0)。它不仅内存更短(较小的代码=更快的加载),而且执行速度也快于复制值(而且CPU现在足够聪明,可以让它更快)。额外的优势是风格点。

计数器结果?计数器寄存器是作为循环计数器而不是数据计数器。为了更直观地存储数据DX或BX(BX比DS更直观,因为不再需要此寄存器中的数据,所以它"只是变量")。但若CX中的结果是必需的,那个么你们必须服从,我想。

好吧,今晚就到此为止。如果有什么不清楚的地方,请留下评论。

最新更新