关于汇编:使用bx寄存器保存索引是否可以?

Is it ok to use bx register to save an index?

在汇编过程中,我有一个任务来计算字符串中的单词数,我需要将我的答案保存在cx寄存器中。(我正在使用80x86处理器)

所以我设定:

cx到0-这是我的计数器

BX到0-这是我的索引

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
.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设置为一个…我并不真正理解这个解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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,因此必须确保不存储数据您的程序仍然需要(或推后弹出)在寄存器中这将被修改。
  • 并非所有的寄存器都允许您(直接)访问8bit部件。
  • 有些寄存器有很酷的专门功能,因此折衷一下,你需要正确地使用它们。

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

  • AX-累加器寄存器通常用作主要参数和结果。在更简单的日子里,x86仍然是听说处理器通常有两个参数寄存器,例如。准将64上的X和Y,以及用于存储结果的累加器。在简而言之,它的名字现在大部分是历史性的,而且通常首先注册你几乎所有的东西-例如算术/逻辑运算和DOS(21h)中断参数通过ah(ax的高字节)。除了那些需要通过AX传递值您可以将其视为主要值变量。
  • dx-数据寄存器-这里不需要太多描述,它存储数据。我决定把它列在AX之后,因为这两个一起工作通常-例如mul(乘法)使用dx存储数据从斧头溢出。是的,它的"just"次变量。
  • cx-计数器寄存器-也很简单,它只是另一个通用寄存器。不过这次是用的特别是作为计数器(顾名思义),通过诸如循环(循环族操作数)和字符串指令(rep族操作数)。只要不使用修改cx的指令你可以随心所欲地使用它(但一定要检查没有更好的数据点)。
  • BX-基址寄存器-长话短说,自从32位到达后,这个寄存器就失去了"偏移"内存地址的功能。所以它是"自由"寄存器,主要存在于向后兼容性。可怜的家伙。请使用它,不要让历史的迷雾吞下这么小的勇敢T?O?A?S?T?E?R?寄存器。
  • 禁止注册!是的,有这样的。好的。

  • sp和bp—栈和基指针—默认方法是不直接使用它们,它们由push处理,管理堆栈的弹出、调用和返回指令,并允许您使用函数。然而,它们可以被用于异端把戏用黑暗魔法,你敢亵渎神圣的堆栈框架吗?改变这些寄存器的值可能导致实际堆栈溢出。不要使用除非你真的,真的确定你想要它(并且知道怎么做)。(在某些情况下,bp可以成为另一个"免费"寄存器,比如bx,但现在让我们忽略它)
  • 现在开始部分可怕的寄存器,与恐吓的名字和复杂的操作联系在一起。此外,它们没有上下8位部分可用(但如果需要,您仍然可以使用位掩码提取它们)。好的。

  • DI和SI-目标和源索引-这两个索引用作指向内存块(缓冲区/数组/字符串)的指针etc)用于自动复制/写入数据,包括rep操作或其他基于字符串/数组的。如果你不使用这种混乱然后可以使用DI和SI作为数据寄存器,不能(容易)选择低或高的限制字节。循环操作的完美选择。
  • 段寄存器-cs,ss,ds,es,fs,gs…(哎呀!现在它是他们的整个军队)-尽管故事可能很长,但简短说明-两个主要部分是代码段和数据段。代码段包含代码(令人惊讶,对吗?)以及所有您在其中声明的数据。段通常与用于复制数据的DI和SI寄存器-例如,lodsd需要SI指向数据段中的内存地址,因此简而言之("flat")代码首先需要通知CPU您的数据和代码段是一个。你真的不应该使用这些寄存器或其他分段错误将踢你在面对。
  • 你可以在这样一本简洁的指南上阅读更多。好的。

    至于你的代码,我现在没有什么建议可以给你(为了全面修改你的脚本,你需要等待明天或周一,因为我这个周末有点忙)好的。

    使用si/di更好。在您的代码中,A[BX]相当于(内存地址)+(SI中的值),CPU是非常简单的生物,因此它更喜欢简单的[SI]而不是动态地进行数学运算。好的。

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

    调零寄存器可以变得更酷!要将0放入AX中吗?使用xor ax,ax(ax=ax exclusive或ax,作为逻辑状态,这将始终导致0)。它不仅内存更短(代码越小=加载越快),而且执行速度也比复制值快(CPU现在的智能足以使它更快)。额外的优势是样式点。好的。

    结果如何?好吧,计数器寄存器是作为循环计数器而不是数据计数器来创建的。为了更直观地存储数据dx或bx(bx比ds多,因为不再需要这个寄存器中的数据,所以它的"只是变量")。但如果结果是必须的,那么你必须服从,我想。好的。

    好吧,今晚就这样。如果有什么不清楚,请留下评论。好的。好啊。